Bug 321171 - support XML sources in XUL templates, r=smaug,sr=peterv CVS: ----------------------------------------------------------------------

This commit is contained in:
enndeakin@sympatico.ca 2007-06-15 08:03:44 -07:00
Родитель 387d40f5b7
Коммит 439d43e8b3
13 изменённых файлов: 1419 добавлений и 149 удалений

Просмотреть файл

@ -103,6 +103,7 @@ GK_ATOM(applyTemplates, "apply-templates")
GK_ATOM(archive, "archive")
GK_ATOM(area, "area")
GK_ATOM(ascending, "ascending")
GK_ATOM(assign, "assign")
GK_ATOM(attribute, "attribute")
GK_ATOM(attributeSet, "attribute-set")
GK_ATOM(aural, "aural")
@ -320,6 +321,7 @@ GK_ATOM(event, "event")
GK_ATOM(events, "events")
GK_ATOM(excludeResultPrefixes, "exclude-result-prefixes")
GK_ATOM(excludes, "excludes")
GK_ATOM(expr, "expr")
GK_ATOM(extends, "extends")
GK_ATOM(extensionElementPrefixes, "extension-element-prefixes")
GK_ATOM(face, "face")

Просмотреть файл

@ -87,6 +87,9 @@ CPPSRCS = \
nsXULTemplateQueryProcessorRDF.cpp \
nsXULTemplateResultRDF.cpp \
nsXULTemplateResultSetRDF.cpp \
nsXMLBinding.cpp \
nsXULTemplateQueryProcessorXML.cpp \
nsXULTemplateResultXML.cpp \
$(NULL)
# we don't want the shared lib, but we want to force the creation of a static lib.

Просмотреть файл

@ -68,10 +68,8 @@ nsTemplateMatch::RuleMatched(nsTemplateQuerySet* aQuerySet,
nsCOMPtr<nsIDOMNode> rulenode;
aRule->GetRuleNode(getter_AddRefs(rulenode));
if (rulenode) {
nsCOMPtr<nsIDOMNode> querynode = do_QueryInterface(aQuerySet->mQueryNode);
return aResult->RuleMatched(querynode, rulenode);
}
if (rulenode)
return aResult->RuleMatched(aQuerySet->mCompiledQuery, rulenode);
return NS_OK;
}

Просмотреть файл

@ -0,0 +1,152 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Neil Deakin
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsXULTemplateQueryProcessorXML.h"
#include "nsXULTemplateResultXML.h"
#include "nsXMLBinding.h"
NS_IMPL_ADDREF(nsXMLBindingSet);
NS_IMPL_RELEASE(nsXMLBindingSet);
nsresult
nsXMLBindingSet::AddBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr)
{
nsAutoPtr<nsXMLBinding> newbinding(new nsXMLBinding(aVar, aExpr));
NS_ENSURE_TRUE(newbinding, NS_ERROR_OUT_OF_MEMORY);
if (mFirst) {
nsXMLBinding* binding = mFirst;
while (binding) {
// if the target variable is already used in a binding, ignore it
// since it won't be useful for anything
if (binding->mVar == aVar)
return NS_OK;
// add the binding at the end of the list
if (!binding->mNext) {
binding->mNext = newbinding;
break;
}
binding = binding->mNext;
}
}
else {
mFirst = newbinding;
}
return NS_OK;
}
PRInt32
nsXMLBindingSet::LookupTargetIndex(nsIAtom* aTargetVariable,
nsXMLBinding** aBinding)
{
PRInt32 idx = 0;
nsXMLBinding* binding = mFirst;
while (binding) {
if (binding->mVar == aTargetVariable) {
*aBinding = binding;
return idx;
}
idx++;
binding = binding->mNext;
}
*aBinding = nsnull;
return -1;
}
void
nsXMLBindingValues::GetAssignmentFor(nsXULTemplateResultXML* aResult,
nsXMLBinding* aBinding,
PRInt32 aIndex,
PRUint16 aType,
nsIDOMXPathResult** aValue)
{
*aValue = mValues.SafeObjectAt(aIndex);
if (!*aValue) {
nsCOMPtr<nsIDOMNode> contextNode;
aResult->GetNode(getter_AddRefs(contextNode));
if (contextNode) {
nsCOMPtr<nsISupports> resultsupports;
aBinding->mExpr->Evaluate(contextNode, aType,
nsnull, getter_AddRefs(resultsupports));
nsCOMPtr<nsIDOMXPathResult> result = do_QueryInterface(resultsupports);
if (result && mValues.ReplaceObjectAt(result, aIndex))
*aValue = result;
}
}
NS_IF_ADDREF(*aValue);
}
void
nsXMLBindingValues::GetNodeAssignmentFor(nsXULTemplateResultXML* aResult,
nsXMLBinding* aBinding,
PRInt32 aIndex,
nsIDOMNode** aNode)
{
nsCOMPtr<nsIDOMXPathResult> result;
GetAssignmentFor(aResult, aBinding, aIndex,
nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE,
getter_AddRefs(result));
if (result)
result->GetSingleNodeValue(aNode);
else
*aNode = nsnull;
}
void
nsXMLBindingValues::GetStringAssignmentFor(nsXULTemplateResultXML* aResult,
nsXMLBinding* aBinding,
PRInt32 aIndex,
nsAString& aValue)
{
nsCOMPtr<nsIDOMXPathResult> result;
GetAssignmentFor(aResult, aBinding, aIndex,
nsIDOMXPathResult::STRING_TYPE, getter_AddRefs(result));
if (result)
result->GetStringValue(aValue);
else
aValue.Truncate();
}

Просмотреть файл

@ -0,0 +1,170 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Neil Deakin
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsXMLBinding_h__
#define nsXMLBinding_h__
#include "nsAutoPtr.h"
#include "nsIAtom.h"
class nsXULTemplateResultXML;
class nsXMLBindingValues;
/**
* Classes related to storing bindings for XML handling.
*/
/**
* a <binding> description
*/
struct nsXMLBinding {
nsCOMPtr<nsIAtom> mVar;
nsCOMPtr<nsIDOMXPathExpression> mExpr;
nsAutoPtr<nsXMLBinding> mNext;
nsXMLBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr)
: mVar(aVar), mExpr(aExpr), mNext(nsnull)
{
MOZ_COUNT_CTOR(nsXMLBinding);
}
~nsXMLBinding()
{
MOZ_COUNT_DTOR(nsXMLBinding);
}
};
/**
* a collection of <binding> descriptors. This object is refcounted by
* nsXMLBindingValues objects and the query processor.
*/
class nsXMLBindingSet
{
public:
// results hold a reference to a binding set in their
// nsXMLBindingValues fields
nsAutoRefCnt mRefCnt;
// pointer to the first binding in a linked list
nsAutoPtr<nsXMLBinding> mFirst;
public:
nsrefcnt AddRef();
nsrefcnt Release();
NS_DECL_OWNINGTHREAD
/**
* Add a binding to the set
*/
nsresult
AddBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr);
/**
* The nsXMLBindingValues class stores an array of values, one for each
* target symbol that could be set by the bindings in the set.
* LookupTargetIndex determines the index into the array for a given
* target symbol.
*/
PRInt32
LookupTargetIndex(nsIAtom* aTargetVariable, nsXMLBinding** aBinding);
};
/**
* a set of values of bindings. This object is used once per result.
*/
class nsXMLBindingValues
{
protected:
// the binding set
nsRefPtr<nsXMLBindingSet> mBindings;
/**
* A set of values for variable bindings. To look up a binding value,
* scan through the binding set in mBindings for the right target atom.
* Its index will correspond to the index in this array.
*/
nsCOMArray<nsIDOMXPathResult> mValues;
public:
nsXMLBindingValues() { MOZ_COUNT_CTOR(nsXMLBindingValues); }
~nsXMLBindingValues() { MOZ_COUNT_DTOR(nsXMLBindingValues); }
nsXMLBindingSet* GetBindingSet() { return mBindings; }
void SetBindingSet(nsXMLBindingSet* aBindings) { mBindings = aBindings; }
PRInt32
LookupTargetIndex(nsIAtom* aTargetVariable, nsXMLBinding** aBinding)
{
return mBindings ?
mBindings->LookupTargetIndex(aTargetVariable, aBinding) : -1;
}
/**
* Retrieve the assignment for a particular variable
*
* aResult the result generated from the template
* aBinding the binding looked up using LookupTargetIndex
* aIndex the index of the assignment to retrieve
* aType the type of result expected
* aValue the value of the assignment
*/
void
GetAssignmentFor(nsXULTemplateResultXML* aResult,
nsXMLBinding* aBinding,
PRInt32 idx,
PRUint16 type,
nsIDOMXPathResult** aValue);
void
GetNodeAssignmentFor(nsXULTemplateResultXML* aResult,
nsXMLBinding* aBinding,
PRInt32 idx,
nsIDOMNode** aValue);
void
GetStringAssignmentFor(nsXULTemplateResultXML* aResult,
nsXMLBinding* aBinding,
PRInt32 idx,
nsAString& aValue);
};
#endif // nsXMLBinding_h__

Просмотреть файл

@ -944,9 +944,12 @@ nsXULContentBuilder::AddPersistentAttributes(nsIContent* aTemplateNode,
nsIXULTemplateResult* aResult,
nsIContent* aRealNode)
{
if (!mRoot)
return NS_OK;
nsCOMPtr<nsIRDFResource> resource;
nsresult rv = GetResultResource(aResult, getter_AddRefs(resource));
if (NS_FAILED(rv)) return rv;
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString attribute, persist;
aTemplateNode->GetAttr(kNameSpaceID_None, nsGkAtoms::persist, persist);
@ -987,11 +990,11 @@ nsXULContentBuilder::AddPersistentAttributes(nsIContent* aTemplateNode,
nsCOMPtr<nsIRDFResource> property;
rv = nsXULContentUtils::GetResource(nameSpaceID, tag, getter_AddRefs(property));
if (NS_FAILED(rv)) return rv;
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIRDFNode> target;
rv = mDB->GetTarget(resource, property, PR_TRUE, getter_AddRefs(target));
if (NS_FAILED(rv)) return rv;
NS_ENSURE_SUCCESS(rv, rv);
if (! target)
continue;
@ -1003,11 +1006,11 @@ nsXULContentBuilder::AddPersistentAttributes(nsIContent* aTemplateNode,
const PRUnichar* valueStr;
rv = value->GetValueConst(&valueStr);
if (NS_FAILED(rv)) return rv;
NS_ENSURE_SUCCESS(rv, rv);
rv = aRealNode->SetAttr(nameSpaceID, tag, nsDependentString(valueStr),
PR_FALSE);
if (NS_FAILED(rv)) return rv;
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
@ -1137,7 +1140,7 @@ nsXULContentBuilder::CreateTemplateAndContainerContents(nsIContent* aElement,
mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::ref, ref);
if (! ref.IsEmpty()) {
nsresult rv = mQueryProcessor->TranslateRef(mDB, ref,
nsresult rv = mQueryProcessor->TranslateRef(mDataSource, ref,
getter_AddRefs(mRootResult));
if (NS_FAILED(rv))
return rv;
@ -1278,7 +1281,7 @@ nsXULContentBuilder::CreateContainerContentsForQuerySet(nsIContent* aElement,
return NS_OK;
nsCOMPtr<nsISimpleEnumerator> results;
nsresult rv = mQueryProcessor->GenerateResults(mDB, aResult,
nsresult rv = mQueryProcessor->GenerateResults(mDataSource, aResult,
aQuerySet->mCompiledQuery,
getter_AddRefs(results));
if (NS_FAILED(rv) || !results)

Просмотреть файл

@ -62,6 +62,8 @@
#include "nsIDOMElement.h"
#include "nsIDOMNode.h"
#include "nsIDOMDocument.h"
#include "nsIDOMXMLDocument.h"
#include "nsIPrivateDOMImplementation.h"
#include "nsIDOMXULElement.h"
#include "nsIDocument.h"
#include "nsBindingManager.h"
@ -99,6 +101,7 @@
#include "nsNetUtil.h"
#include "nsXULTemplateBuilder.h"
#include "nsXULTemplateQueryProcessorRDF.h"
#include "nsXULTemplateQueryProcessorXML.h"
//----------------------------------------------------------------------
@ -128,10 +131,7 @@ PRLogModuleInfo* gXULTemplateLog;
//
nsXULTemplateBuilder::nsXULTemplateBuilder(void)
: mDB(nsnull),
mCompDB(nsnull),
mRoot(nsnull),
mQueriesCompiled(PR_FALSE),
: mQueriesCompiled(PR_FALSE),
mFlags(0),
mTop(nsnull)
{
@ -246,10 +246,12 @@ TraverseMatchList(nsISupports* aKey, nsTemplateMatch* aMatch, void* aContext)
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTemplateBuilder)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULTemplateBuilder)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDataSource)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDB)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCompDB)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULTemplateBuilder)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDataSource)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDB)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCompDB)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRoot)
@ -300,7 +302,7 @@ nsXULTemplateBuilder::GetRoot(nsIDOMElement** aResult)
NS_IMETHODIMP
nsXULTemplateBuilder::GetDatabase(nsIRDFCompositeDataSource** aResult)
{
NS_IF_ADDREF(*aResult = mCompDB.get());
NS_IF_ADDREF(*aResult = mCompDB);
return NS_OK;
}
@ -364,6 +366,9 @@ nsXULTemplateBuilder::Refresh()
{
nsresult rv;
if (!mCompDB)
return NS_ERROR_FAILURE;
nsCOMPtr<nsISimpleEnumerator> dslist;
rv = mCompDB->GetDataSources(getter_AddRefs(dslist));
NS_ENSURE_SUCCESS(rv, rv);
@ -396,36 +401,14 @@ nsXULTemplateBuilder::Init(nsIContent* aElement)
if (! doc)
return NS_ERROR_UNEXPECTED;
nsresult rv = LoadDataSources(doc);
PRBool shouldDelay;
nsresult rv = LoadDataSources(doc, &shouldDelay);
if (NS_SUCCEEDED(rv)) {
// Add ourselves as a document observer
doc->AddObserver(this);
}
// create the query processor. The querytype attribute on the root element
// may be used to create one of a specific type.
// XXX should non-chrome be restricted to specific names?
nsAutoString type;
mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::querytype, type);
if (type.IsEmpty() || type.EqualsLiteral("rdf")) {
mQueryProcessor = new nsXULTemplateQueryProcessorRDF();
if (! mQueryProcessor)
return NS_ERROR_OUT_OF_MEMORY;
}
else {
nsCAutoString cid(NS_QUERY_PROCESSOR_CONTRACTID_PREFIX);
AppendUTF16toUTF8(type, cid);
mQueryProcessor = do_CreateInstance(cid.get(), &rv);
if (!mQueryProcessor) {
// XXXndeakin should log an error here
return rv;
}
}
return rv;
}
@ -1066,8 +1049,10 @@ nsXULTemplateBuilder::AttributeChanged(nsIDocument* aDocument,
// Check for a change to the 'datasources' attribute. If so, setup
// mDB by parsing the vew value and rebuild.
else if (aAttribute == nsGkAtoms::datasources) {
LoadDataSources(aDocument);
Rebuild();
PRBool shouldDelay;
LoadDataSources(aDocument, &shouldDelay);
if (!shouldDelay)
Rebuild();
}
}
}
@ -1118,6 +1103,7 @@ nsXULTemplateBuilder::NodeWillBeDestroyed(const nsINode* aNode)
if (mQueryProcessor)
mQueryProcessor->Done();
mDataSource = nsnull;
mDB = nsnull;
mCompDB = nsnull;
mRoot = nsnull;
@ -1134,57 +1120,144 @@ nsXULTemplateBuilder::NodeWillBeDestroyed(const nsINode* aNode)
//
nsresult
nsXULTemplateBuilder::LoadDataSources(nsIDocument* doc)
nsXULTemplateBuilder::LoadDataSources(nsIDocument* aDocument,
PRBool* aShouldDelayBuilding)
{
NS_PRECONDITION(mRoot != nsnull, "not initialized");
nsresult rv;
PRBool isRDFQuery = PR_FALSE;
// we'll set these again later, after we create a new composite ds
mDB = nsnull;
mCompDB = nsnull;
mDataSource = nsnull;
if (mDB) {
// we'll set it again later, after we create a new composite ds
mDB = nsnull;
*aShouldDelayBuilding = PR_TRUE;
nsAutoString datasources;
mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::datasources, datasources);
nsAutoString querytype;
mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::querytype, querytype);
// if the datasources begins with '#', it is a reference to a node
// within the same document.
PRBool shouldLoadUrls = PR_TRUE;
if (datasources.CharAt(0) == '#') {
shouldLoadUrls = PR_FALSE;
if (querytype.IsEmpty()) {
querytype.AssignLiteral("xml");
}
nsCOMPtr<nsIDOMDocument> domdoc = do_QueryInterface(aDocument);
nsCOMPtr<nsIDOMElement> dsnode;
domdoc->GetElementById(Substring(datasources, 1),
getter_AddRefs(dsnode));
if (dsnode) {
mDataSource = dsnode;
*aShouldDelayBuilding = PR_FALSE;
}
}
// create the query processor. The querytype attribute on the root element
// may be used to create one of a specific type.
// XXX should non-chrome be restricted to specific names?
if (querytype.IsEmpty())
querytype.AssignLiteral("rdf");
if (querytype.EqualsLiteral("rdf")) {
isRDFQuery = PR_TRUE;
mQueryProcessor = new nsXULTemplateQueryProcessorRDF();
NS_ENSURE_TRUE(mQueryProcessor, NS_ERROR_OUT_OF_MEMORY);
}
else if (querytype.EqualsLiteral("xml")) {
mQueryProcessor = new nsXULTemplateQueryProcessorXML();
NS_ENSURE_TRUE(mQueryProcessor, NS_ERROR_OUT_OF_MEMORY);
}
else {
shouldLoadUrls = PR_FALSE;
nsCAutoString cid(NS_QUERY_PROCESSOR_CONTRACTID_PREFIX);
AppendUTF16toUTF8(querytype, cid);
mQueryProcessor = do_CreateInstance(cid.get(), &rv);
// XXXndeakin log an error here - bug 321169
NS_ENSURE_TRUE(mQueryProcessor, rv);
}
// create a database for the builder
mCompDB = do_CreateInstance(NS_RDF_DATASOURCE_CONTRACTID_PREFIX "composite-datasource");
if (! mCompDB) {
NS_ERROR("unable to construct new composite data source");
return NS_ERROR_UNEXPECTED;
if (shouldLoadUrls) {
rv = LoadDataSourceUrls(aDocument, datasources,
isRDFQuery, aShouldDelayBuilding);
NS_ENSURE_SUCCESS(rv, rv);
}
// check for magical attributes. XXX move to ``flags''?
if (mRoot->AttrValueIs(kNameSpaceID_None, nsGkAtoms::coalesceduplicatearcs,
nsGkAtoms::_false, eCaseMatters))
mCompDB->SetCoalesceDuplicateArcs(PR_FALSE);
if (mRoot->AttrValueIs(kNameSpaceID_None, nsGkAtoms::allownegativeassertions,
nsGkAtoms::_false, eCaseMatters))
mCompDB->SetAllowNegativeAssertions(PR_FALSE);
// Now set the database on the element, so that script writers can
// access it.
nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(aDocument);
if (xuldoc)
xuldoc->SetTemplateBuilderFor(mRoot, this);
if (!mRoot->IsNodeOfType(nsINode::eXUL)) {
// Hmm. This must be an HTML element. Try to set it as a
// JS property "by hand".
InitHTMLTemplateRoot();
}
return NS_OK;
}
nsresult
nsXULTemplateBuilder::LoadDataSourceUrls(nsIDocument* aDocument,
const nsAString& aDataSources,
PRBool aIsRDFQuery,
PRBool* aShouldDelayBuilding)
{
// Grab the doc's principal...
nsIPrincipal *docPrincipal = doc->NodePrincipal();
nsIPrincipal *docPrincipal = aDocument->NodePrincipal();
NS_ASSERTION(docPrincipal == mRoot->NodePrincipal(),
"Principal mismatch? Which one to use?");
PRBool isTrusted = PR_FALSE;
rv = IsSystemPrincipal(docPrincipal, &isTrusted);
if (NS_FAILED(rv))
return rv;
nsresult rv = IsSystemPrincipal(docPrincipal, &isTrusted);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIRDFDataSource> localstore;
if (isTrusted) {
// If we're a privileged (e.g., chrome) document, then add the
// local store as the first data source in the db. Note that
// we _might_ not be able to get a local store if we haven't
// got a profile to read from yet.
nsCOMPtr<nsIRDFDataSource> localstore;
rv = gRDFService->GetDataSource("rdf:local-store", getter_AddRefs(localstore));
if (NS_SUCCEEDED(rv)) {
NS_ENSURE_SUCCESS(rv, rv);
}
if (aIsRDFQuery) {
// create a database for the builder
mCompDB = do_CreateInstance(NS_RDF_DATASOURCE_CONTRACTID_PREFIX "composite-datasource");
if (! mCompDB) {
NS_ERROR("unable to construct new composite data source");
return NS_ERROR_UNEXPECTED;
}
// check for magical attributes. XXX move to ``flags''?
if (mRoot->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::coalesceduplicatearcs,
nsGkAtoms::_false, eCaseMatters))
mCompDB->SetCoalesceDuplicateArcs(PR_FALSE);
if (mRoot->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::allownegativeassertions,
nsGkAtoms::_false, eCaseMatters))
mCompDB->SetAllowNegativeAssertions(PR_FALSE);
if (localstore) {
// If we're a privileged (e.g., chrome) document, then add the
// local store as the first data source in the db. Note that
// we _might_ not be able to get a local store if we haven't
// got a profile to read from yet.
rv = mCompDB->AddDataSource(localstore);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to add local store to db");
if (NS_FAILED(rv))
return rv;
NS_ENSURE_SUCCESS(rv, rv);
}
}
@ -1193,14 +1266,11 @@ nsXULTemplateBuilder::LoadDataSources(nsIDocument* doc)
//
// rdf:bookmarks rdf:history http://foo.bar.com/blah.cgi?baz=9
//
nsIURI *docurl = doc->GetDocumentURI();
nsAutoString datasources;
mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::datasources, datasources);
nsIURI *docurl = aDocument->GetDocumentURI();
nsAutoString datasources(aDataSources);
PRUint32 first = 0;
while(1) {
while (1) {
while (first < datasources.Length() && nsCRT::IsAsciiSpace(datasources.CharAt(first)))
++first;
@ -1223,6 +1293,7 @@ nsXULTemplateBuilder::LoadDataSources(nsIDocument* doc)
// protocol) leaves uriStr unaltered.
NS_MakeAbsoluteURI(uriStr, uriStr, docurl);
nsCOMPtr<nsIPrincipal> principal;
if (!isTrusted) {
// Our document is untrusted, so check to see if we can
// load the datasource that they've asked for.
@ -1231,17 +1302,14 @@ nsXULTemplateBuilder::LoadDataSources(nsIDocument* doc)
if (NS_FAILED(rv) || !uri)
continue; // Necko will barf if our URI is weird
nsCOMPtr<nsIPrincipal> principal;
rv = gScriptSecurityManager->GetCodebasePrincipal(uri, getter_AddRefs(principal));
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get codebase principal");
if (NS_FAILED(rv))
return rv;
NS_ENSURE_SUCCESS(rv, rv);
PRBool same;
rv = docPrincipal->Equals(principal, &same);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to test same origin");
if (NS_FAILED(rv))
return rv;
NS_ENSURE_SUCCESS(rv, rv);
if (! same)
continue;
@ -1251,64 +1319,90 @@ nsXULTemplateBuilder::LoadDataSources(nsIDocument* doc)
// document. Let it load!
}
nsCOMPtr<nsIRDFDataSource> ds;
nsCAutoString uristrC;
uristrC.AssignWithConversion(uriStr);
if (aIsRDFQuery) {
nsCOMPtr<nsIRDFDataSource> ds;
nsCAutoString uristrC;
uristrC.AssignWithConversion(uriStr);
rv = gRDFService->GetDataSource(uristrC.get(), getter_AddRefs(ds));
rv = gRDFService->GetDataSource(uristrC.get(), getter_AddRefs(ds));
if (NS_FAILED(rv)) {
// This is only a warning because the data source may not
// be accessible for any number of reasons, including
// security, a bad URL, etc.
#ifdef DEBUG
nsCAutoString msg;
msg.Append("unable to load datasource '");
msg.AppendWithConversion(uriStr);
msg.Append('\'');
NS_WARNING(msg.get());
#endif
continue;
if (NS_FAILED(rv)) {
// This is only a warning because the data source may not
// be accessible for any number of reasons, including
// security, a bad URL, etc.
#ifdef DEBUG
nsCAutoString msg;
msg.Append("unable to load datasource '");
msg.AppendWithConversion(uriStr);
msg.Append('\'');
NS_WARNING(msg.get());
#endif
continue;
}
mCompDB->AddDataSource(ds);
}
else {
nsAutoString emptyStr;
nsCOMPtr<nsIDOMDocument> domDocument;
rv = nsContentUtils::CreateDocument(emptyStr, emptyStr, nsnull,
docurl, aDocument->GetBaseURI(),
docPrincipal,
getter_AddRefs(domDocument));
NS_ENSURE_SUCCESS(rv, rv);
mCompDB->AddDataSource(ds);
}
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(domDocument);
target->AddEventListener(NS_LITERAL_STRING("load"), this, PR_FALSE);
nsCOMPtr<nsIDOMXMLDocument> xmldoc = do_QueryInterface(domDocument);
// check if we were given an inference engine type
nsAutoString infer;
mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::infer, infer);
if (!infer.IsEmpty()) {
nsCString inferContractID(NS_RDF_INFER_DATASOURCE_CONTRACTID_PREFIX);
AppendUTF16toUTF8(infer, inferContractID);
nsCOMPtr<nsIRDFInferDataSource> inferDB = do_CreateInstance(inferContractID.get());
if (inferDB) {
inferDB->SetBaseDataSource(mCompDB);
mDB = do_QueryInterface(inferDB);
} else {
NS_WARNING("failed to construct inference engine specified on template");
PRBool ok;
xmldoc->Load(uriStr, &ok);
if (ok) {
mDataSource = domDocument;
*aShouldDelayBuilding = PR_TRUE;
}
// only one XML datasource is supported currently
break;
}
}
if (aIsRDFQuery) {
// check if we were given an inference engine type
nsAutoString infer;
mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::infer, infer);
if (!infer.IsEmpty()) {
nsCString inferCID(NS_RDF_INFER_DATASOURCE_CONTRACTID_PREFIX);
AppendUTF16toUTF8(infer, inferCID);
nsCOMPtr<nsIRDFInferDataSource> inferDB =
do_CreateInstance(inferCID.get());
if (!mDB)
mDB = mCompDB;
nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(doc);
if (xuldoc)
xuldoc->SetTemplateBuilderFor(mRoot, this);
// Now set the database on the element, so that script writers can
// access it.
nsXULElement *xulcontent = nsXULElement::FromContent(mRoot);
if (! xulcontent) {
// Hmm. This must be an HTML element. Try to set it as a
// JS property "by hand".
InitHTMLTemplateRoot();
if (inferDB) {
inferDB->SetBaseDataSource(mCompDB);
mDB = do_QueryInterface(inferDB);
} else {
NS_WARNING("failed to construct inference engine specified on template");
}
}
if (!mDB)
mDB = mCompDB;
mDataSource = mDB;
}
else {
mDB = localstore;
}
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateBuilder::HandleEvent(nsIDOMEvent* aEvent)
{
return Rebuild();
}
nsresult
nsXULTemplateBuilder::InitHTMLTemplateRoot()
{
@ -1348,7 +1442,7 @@ nsXULTemplateBuilder::InitHTMLTemplateRoot()
rv = wrapper->GetJSObject(&jselement);
NS_ENSURE_SUCCESS(rv, rv);
{
if (mDB) {
// database
rv = xpc->WrapNative(jscontext, scope, mDB,
NS_GET_IID(nsIRDFCompositeDataSource),
@ -1687,7 +1781,8 @@ nsXULTemplateBuilder::CompileQueries()
mFlags |= eDontRecurse;
nsCOMPtr<nsIDOMNode> rootnode = do_QueryInterface(mRoot);
nsresult rv = mQueryProcessor->InitializeForBuilding(mDB, this, rootnode);
nsresult rv =
mQueryProcessor->InitializeForBuilding(mDataSource, this, rootnode);
if (NS_FAILED(rv))
return rv;
@ -1989,14 +2084,15 @@ nsXULTemplateBuilder::CompileExtendedQuery(nsIContent* aRuleElement,
nsGkAtoms::conditions,
getter_AddRefs(conditions));
if (conditions) {
rv = CompileConditions(rule, conditions);
// If the rule compilation failed, then we have to bail.
if (NS_FAILED(rv)) {
delete rule;
return rv;
}
// allow the conditions to be placed directly inside the rule
if (!conditions)
conditions = aRuleElement;
rv = CompileConditions(rule, conditions);
// If the rule compilation failed, then we have to bail.
if (NS_FAILED(rv)) {
delete rule;
return rv;
}
rv = aQuerySet->AddRule(rule);
@ -2014,11 +2110,12 @@ nsXULTemplateBuilder::CompileExtendedQuery(nsIContent* aRuleElement,
nsGkAtoms::bindings,
getter_AddRefs(bindings));
if (bindings) {
rv = CompileBindings(rule, bindings);
if (NS_FAILED(rv))
return rv;
}
// allow bindings to be placed directly inside rule
if (!bindings)
bindings = aRuleElement;
rv = CompileBindings(rule, bindings);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}

Просмотреть файл

@ -53,6 +53,7 @@
#include "nsIRDFObserver.h"
#include "nsIRDFService.h"
#include "nsIXULTemplateBuilder.h"
#include "nsIDOMEventListener.h"
#include "nsFixedSizeAllocator.h"
#include "nsVoidArray.h"
@ -77,6 +78,7 @@ class nsIRDFCompositeDataSource;
* set of rules.
*/
class nsXULTemplateBuilder : public nsIXULTemplateBuilder,
public nsIDOMEventListener,
public nsStubDocumentObserver
{
public:
@ -98,7 +100,9 @@ public:
// nsIXULTemplateBuilder interface
NS_DECL_NSIXULTEMPLATEBUILDER
NS_DECL_NSIDOMEVENTLISTENER
// nsIDocumentObserver
virtual void AttributeChanged(nsIDocument *aDocument, nsIContent* aContent,
PRInt32 aNameSpaceID, nsIAtom* aAttribute,
@ -274,8 +278,30 @@ public:
const nsAString& aVariable,
void* aClosure);
/**
* Load the datasources for the template. shouldDelayBuilding is an out
* parameter which will be set to true to indicate that content building
* should not be performed yet as the datasource has not yet loaded. If
* false, the datasource has already loaded so building can proceed
* immediately. In the former case, the datasource or query processor
* should either rebuild the template or update results when the
* datasource is loaded as needed.
*/
nsresult
LoadDataSources(nsIDocument* aDoc);
LoadDataSources(nsIDocument* aDoc, PRBool* shouldDelayBuilding);
/**
* Called by LoadDataSources to load a datasource given a uri list
* in aDataSource. The list is a set of uris separated by spaces.
* If aIsRDFQuery is true, then this is for an RDF datasource which
* causes the method to check for additional flags specific to the
* RDF processor.
*/
nsresult
LoadDataSourceUrls(nsIDocument* aDocument,
const nsAString& aDataSources,
PRBool aIsRDFQuery,
PRBool* aShouldDelayBuilding);
nsresult
InitHTMLTemplateRoot();
@ -330,6 +356,7 @@ public:
nsIRDFResource** aResource);
protected:
nsCOMPtr<nsISupports> mDataSource;
nsCOMPtr<nsIRDFDataSource> mDB;
nsCOMPtr<nsIRDFCompositeDataSource> mCompDB;

Просмотреть файл

@ -0,0 +1,345 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Neil Deakin
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsIDOMDocument.h"
#include "nsIDOMNode.h"
#include "nsIDOMNodeList.h"
#include "nsIDOMElement.h"
#include "nsIDOMXPathNSResolver.h"
#include "nsINameSpaceManager.h"
#include "nsGkAtoms.h"
#include "nsIServiceManager.h"
#include "nsUnicharUtils.h"
#include "nsXULTemplateBuilder.h"
#include "nsXULTemplateQueryProcessorXML.h"
#include "nsXULTemplateResultXML.h"
NS_IMPL_ISUPPORTS1(nsXMLQuery, nsXMLQuery)
//----------------------------------------------------------------------
//
// nsXULTemplateResultSetXML
//
NS_IMPL_ISUPPORTS1(nsXULTemplateResultSetXML, nsISimpleEnumerator)
NS_IMETHODIMP
nsXULTemplateResultSetXML::HasMoreElements(PRBool *aResult)
{
// if GetSnapshotLength failed, then the return type was not a set of
// nodes, so just return false in this case.
PRUint32 length;
if (NS_SUCCEEDED(mResults->GetSnapshotLength(&length)))
*aResult = (mPosition < length);
else
*aResult = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultSetXML::GetNext(nsISupports **aResult)
{
nsCOMPtr<nsIDOMNode> node;
nsresult rv = mResults->SnapshotItem(mPosition, getter_AddRefs(node));
NS_ENSURE_SUCCESS(rv, rv);
nsXULTemplateResultXML* result =
new nsXULTemplateResultXML(mQuery, node, mBindingSet);
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
++mPosition;
*aResult = result;
NS_ADDREF(result);
return NS_OK;
}
//----------------------------------------------------------------------
//
// nsXULTemplateQueryProcessorXML
//
NS_IMPL_ISUPPORTS1(nsXULTemplateQueryProcessorXML, nsIXULTemplateQueryProcessor)
NS_IMETHODIMP
nsXULTemplateQueryProcessorXML::InitializeForBuilding(nsISupports* aDatasource,
nsIXULTemplateBuilder* aBuilder,
nsIDOMNode* aRootNode)
{
// the datasource is either a document or a DOM element
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDatasource);
if (doc)
doc->GetDocumentElement(getter_AddRefs(mRoot));
else
mRoot = do_QueryInterface(aDatasource);
NS_ENSURE_STATE(mRoot);
mEvaluator = do_CreateInstance("@mozilla.org/dom/xpath-evaluator;1");
NS_ENSURE_TRUE(mEvaluator, NS_ERROR_OUT_OF_MEMORY);
if (!mRuleToBindingsMap.IsInitialized() &&
!mRuleToBindingsMap.Init())
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorXML::Done()
{
mGenerationStarted = PR_FALSE;
if (mRuleToBindingsMap.IsInitialized())
mRuleToBindingsMap.Clear();
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorXML::CompileQuery(nsIXULTemplateBuilder* aBuilder,
nsIDOMNode* aQueryNode,
nsIAtom* aRefVariable,
nsIAtom* aMemberVariable,
nsISupports** _retval)
{
nsresult rv = NS_OK;
*_retval = nsnull;
nsCOMPtr<nsIContent> content = do_QueryInterface(aQueryNode);
nsAutoString expr;
content->GetAttr(kNameSpaceID_None, nsGkAtoms::expr, expr);
// if an expression is not specified, then the default is to
// just take all of the children
if (expr.IsEmpty())
expr.AssignLiteral("*");
nsCOMPtr<nsIDOMXPathExpression> compiledexpr;
rv = CreateExpression(expr, aQueryNode, getter_AddRefs(compiledexpr));
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<nsXMLQuery> query =
new nsXMLQuery(this, aMemberVariable, compiledexpr);
NS_ENSURE_TRUE(query, NS_ERROR_OUT_OF_MEMORY);
PRUint32 count = content->GetChildCount();
for (PRUint32 i = 0; i < count; ++i) {
nsIContent *condition = content->GetChildAt(i);
if (condition->NodeInfo()->Equals(nsGkAtoms::assign,
kNameSpaceID_XUL)) {
nsAutoString var;
condition->GetAttr(kNameSpaceID_None, nsGkAtoms::var, var);
nsAutoString expr;
condition->GetAttr(kNameSpaceID_None, nsGkAtoms::expr, expr);
// ignore assignments without a variable or an expression
if (!var.IsEmpty() && !expr.IsEmpty()) {
nsCOMPtr<nsIDOMNode> conditionNode =
do_QueryInterface(condition);
rv = CreateExpression(expr, conditionNode,
getter_AddRefs(compiledexpr));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAtom> varatom = do_GetAtom(var);
rv = query->AddBinding(varatom, compiledexpr);
NS_ENSURE_SUCCESS(rv, rv);
}
}
}
*_retval = query;
NS_ADDREF(*_retval);
return rv;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorXML::GenerateResults(nsISupports* aDatasource,
nsIXULTemplateResult* aRef,
nsISupports* aQuery,
nsISimpleEnumerator** aResults)
{
if (!aQuery)
return NS_ERROR_INVALID_ARG;
mGenerationStarted = PR_TRUE;
nsCOMPtr<nsXMLQuery> xmlquery = do_QueryInterface(aQuery);
if (!xmlquery)
return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsIDOMNode> context;
aRef->GetBindingObjectFor(xmlquery->GetMemberVariable(),
getter_AddRefs(context));
if (!context)
context = mRoot;
nsIDOMXPathExpression* expr = xmlquery->GetResultsExpression();
if (!expr)
return NS_ERROR_FAILURE;
nsCOMPtr<nsISupports> exprsupportsresults;
nsresult rv = expr->Evaluate(context,
nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE,
nsnull, getter_AddRefs(exprsupportsresults));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMXPathResult> exprresults =
do_QueryInterface(exprsupportsresults);
nsXULTemplateResultSetXML* results =
new nsXULTemplateResultSetXML(xmlquery, exprresults,
xmlquery->GetBindingSet());
NS_ENSURE_TRUE(results, NS_ERROR_OUT_OF_MEMORY);
*aResults = results;
NS_ADDREF(*aResults);
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorXML::AddBinding(nsIDOMNode* aRuleNode,
nsIAtom* aVar,
nsIAtom* aRef,
const nsAString& aExpr)
{
if (mGenerationStarted)
return NS_ERROR_FAILURE;
nsRefPtr<nsXMLBindingSet> bindings = mRuleToBindingsMap.GetWeak(aRuleNode);
if (!bindings) {
bindings = new nsXMLBindingSet();
if (!bindings || !mRuleToBindingsMap.Put(aRuleNode, bindings))
return NS_ERROR_OUT_OF_MEMORY;
}
nsCOMPtr<nsIDOMXPathExpression> compiledexpr;
nsresult rv =
CreateExpression(aExpr, aRuleNode, getter_AddRefs(compiledexpr));
NS_ENSURE_SUCCESS(rv, rv);
// aRef isn't currently used for XML query processors
return bindings->AddBinding(aVar, compiledexpr);
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorXML::TranslateRef(nsISupports* aDatasource,
const nsAString& aRefString,
nsIXULTemplateResult** aRef)
{
*aRef = nsnull;
// the datasource is either a document or a DOM element
nsCOMPtr<nsIDOMElement> rootElement;
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDatasource);
if (doc)
doc->GetDocumentElement(getter_AddRefs(rootElement));
else
rootElement = do_QueryInterface(aDatasource);
// if no root element, just return. The document may not have loaded yet
if (!rootElement)
return NS_OK;
nsXULTemplateResultXML* result =
new nsXULTemplateResultXML(nsnull, rootElement, nsnull);
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
*aRef = result;
NS_ADDREF(*aRef);
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateQueryProcessorXML::CompareResults(nsIXULTemplateResult* aLeft,
nsIXULTemplateResult* aRight,
nsIAtom* aVar,
PRInt32* aResult)
{
*aResult = 0;
// XXXndeakin - bug 379745
// it would be good for this to handle other types such as integers,
// so that sorting can be optimized for different types.
nsAutoString leftVal;
aLeft->GetBindingFor(aVar, leftVal);
nsAutoString rightVal;
aRight->GetBindingFor(aVar, rightVal);
// currently templates always sort case-insensitive
*aResult = ::Compare(leftVal, rightVal,
nsCaseInsensitiveStringComparator());
return NS_OK;
}
nsXMLBindingSet*
nsXULTemplateQueryProcessorXML::GetOptionalBindingsForRule(nsIDOMNode* aRuleNode)
{
return mRuleToBindingsMap.GetWeak(aRuleNode);
}
nsresult
nsXULTemplateQueryProcessorXML::CreateExpression(const nsAString& aExpr,
nsIDOMNode* aNode,
nsIDOMXPathExpression** aCompiledExpr)
{
nsCOMPtr<nsIDOMXPathNSResolver> nsResolver;
nsCOMPtr<nsIDOMDocument> doc;
aNode->GetOwnerDocument(getter_AddRefs(doc));
nsCOMPtr<nsIDOMXPathEvaluator> eval = do_QueryInterface(doc);
if (eval) {
nsresult rv =
eval->CreateNSResolver(aNode, getter_AddRefs(nsResolver));
NS_ENSURE_SUCCESS(rv, rv);
}
return mEvaluator->CreateExpression(aExpr, nsResolver, aCompiledExpr);
}

Просмотреть файл

@ -0,0 +1,179 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Neil Deakin
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsXULTemplateQueryProcessorXML_h__
#define nsXULTemplateQueryProcessorXML_h__
#include "nsIXULTemplateQueryProcessor.h"
#include "nsISimpleEnumerator.h"
#include "nsString.h"
#include "nsCOMArray.h"
#include "nsRefPtrHashtable.h"
#include "nsIDOMElement.h"
#include "nsIDOMXPathExpression.h"
#include "nsIDOMXPathEvaluator.h"
#include "nsIDOMXPathResult.h"
#include "nsXMLBinding.h"
class nsXULTemplateQueryProcessorXML;
#define NS_IXMLQUERY_IID \
{0x0358d692, 0xccce, 0x4a97, \
{ 0xb2, 0x51, 0xba, 0x8f, 0x17, 0x0f, 0x3b, 0x6f }}
class nsXMLQuery : public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXMLQUERY_IID)
NS_DECL_ISUPPORTS
// return a weak reference to the processor the query was created from
nsXULTemplateQueryProcessorXML* Processor() { return mProcessor; }
// return a weak reference t the member variable for the query
nsIAtom* GetMemberVariable() { return mMemberVariable; }
// return a weak reference to the expression used to generate results
nsIDOMXPathExpression* GetResultsExpression() { return mResultsExpr; }
// return a weak reference to the additional required bindings
nsXMLBindingSet* GetBindingSet() { return mRequiredBindings; }
// add a required binding for the query
nsresult
AddBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr)
{
if (!mRequiredBindings) {
mRequiredBindings = new nsXMLBindingSet();
NS_ENSURE_TRUE(mRequiredBindings, NS_ERROR_OUT_OF_MEMORY);
}
return mRequiredBindings->AddBinding(aVar, aExpr);
}
nsXMLQuery(nsXULTemplateQueryProcessorXML* aProcessor,
nsIAtom* aMemberVariable,
nsIDOMXPathExpression* aResultsExpr)
: mProcessor(aProcessor),
mMemberVariable(aMemberVariable),
mResultsExpr(aResultsExpr)
{ }
protected:
nsXULTemplateQueryProcessorXML* mProcessor;
nsCOMPtr<nsIAtom> mMemberVariable;
nsCOMPtr<nsIDOMXPathExpression> mResultsExpr;
nsRefPtr<nsXMLBindingSet> mRequiredBindings;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsXMLQuery, NS_IXMLQUERY_IID)
class nsXULTemplateResultSetXML : public nsISimpleEnumerator
{
private:
// reference back to the query
nsCOMPtr<nsXMLQuery> mQuery;
// the binding set created from <assign> nodes
nsRefPtr<nsXMLBindingSet> mBindingSet;
// set of results contained in this enumerator
nsCOMPtr<nsIDOMXPathResult> mResults;
// current position within the list of results
PRUint32 mPosition;
public:
// nsISupports interface
NS_DECL_ISUPPORTS
// nsISimpleEnumerator interface
NS_DECL_NSISIMPLEENUMERATOR
nsXULTemplateResultSetXML(nsXMLQuery* aQuery,
nsIDOMXPathResult* aResults,
nsXMLBindingSet* aBindingSet)
: mQuery(aQuery),
mBindingSet(aBindingSet),
mResults(aResults),
mPosition(0)
{}
};
class nsXULTemplateQueryProcessorXML : public nsIXULTemplateQueryProcessor
{
public:
nsXULTemplateQueryProcessorXML()
: mGenerationStarted(PR_FALSE)
{}
// nsISupports interface
NS_DECL_ISUPPORTS
// nsIXULTemplateQueryProcessor interface
NS_DECL_NSIXULTEMPLATEQUERYPROCESSOR
nsXMLBindingSet*
GetOptionalBindingsForRule(nsIDOMNode* aRuleNode);
// create an XPath expression from aExpr, using aNode for
// resolving namespaces
nsresult
CreateExpression(const nsAString& aExpr,
nsIDOMNode* aNode,
nsIDOMXPathExpression** aCompiledExpr);
private:
PRBool mGenerationStarted;
nsRefPtrHashtable<nsISupportsHashKey, nsXMLBindingSet> mRuleToBindingsMap;
nsCOMPtr<nsIDOMElement> mRoot;
nsCOMPtr<nsIDOMXPathEvaluator> mEvaluator;
};
#endif // nsXULTemplateQueryProcessorXML_h__

Просмотреть файл

@ -0,0 +1,210 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Neil Deakin
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsIServiceManager.h"
#include "nsIDOMNode.h"
#include "nsIDOMElement.h"
#include "nsIContent.h"
#include "nsIRDFService.h"
#include "nsXULTemplateResultXML.h"
#include "nsXMLBinding.h"
static PRUint32 sTemplateId = 0;
NS_IMPL_ISUPPORTS1(nsXULTemplateResultXML, nsIXULTemplateResult)
nsXULTemplateResultXML::nsXULTemplateResultXML(nsXMLQuery* aQuery,
nsIDOMNode* aNode,
nsXMLBindingSet* aBindings)
: mId(++sTemplateId), mQuery(aQuery), mNode(aNode)
{
if (aBindings)
mRequiredValues.SetBindingSet(aBindings);
}
NS_IMETHODIMP
nsXULTemplateResultXML::GetIsContainer(PRBool* aIsContainer)
{
// a node is considered a container if it has children
if (mNode)
mNode->HasChildNodes(aIsContainer);
else
*aIsContainer = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::GetIsEmpty(PRBool* aIsEmpty)
{
// a node is considered empty if it has no elements as children
nsCOMPtr<nsIContent> content = do_QueryInterface(mNode);
if (content) {
PRUint32 count = content->GetChildCount();
for (PRUint32 c = 0; c < count; c++) {
if (content->GetChildAt(c)->IsNodeOfType(nsIContent::eELEMENT)) {
*aIsEmpty = PR_FALSE;
return NS_OK;
}
}
}
*aIsEmpty = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::GetMayProcessChildren(PRBool* aMayProcessChildren)
{
*aMayProcessChildren = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::GetId(nsAString& aId)
{
nsAutoString rowid(NS_LITERAL_STRING("row"));
rowid.AppendInt(mId);
aId.Assign(rowid);
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::GetResource(nsIRDFResource** aResource)
{
*aResource = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::GetType(nsAString& aType)
{
aType.Truncate();
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::GetBindingFor(nsIAtom* aVar, nsAString& aValue)
{
// get the position of the atom in the variables table
nsXMLBinding* binding;
PRInt32 idx = mRequiredValues.LookupTargetIndex(aVar, &binding);
if (idx >= 0) {
mRequiredValues.GetStringAssignmentFor(this, binding, idx, aValue);
return NS_OK;
}
idx = mOptionalValues.LookupTargetIndex(aVar, &binding);
if (idx >= 0) {
mOptionalValues.GetStringAssignmentFor(this, binding, idx, aValue);
return NS_OK;
}
// if the variable is not bound, just use the variable name as the name of
// an attribute to retrieve
nsAutoString attr;
aVar->ToString(attr);
if (attr.Length() > 1) {
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mNode);
if (element)
return element->GetAttribute(Substring(attr, 1), aValue);
}
aValue.Truncate();
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::GetBindingObjectFor(nsIAtom* aVar, nsISupports** aValue)
{
nsXMLBinding* binding;
nsCOMPtr<nsIDOMNode> node;
if (mQuery && aVar == mQuery->GetMemberVariable()) {
node = mNode;
}
else {
PRInt32 idx = mRequiredValues.LookupTargetIndex(aVar, &binding);
if (idx > 0) {
mRequiredValues.GetNodeAssignmentFor(this, binding, idx,
getter_AddRefs(node));
}
else {
idx = mOptionalValues.LookupTargetIndex(aVar, &binding);
if (idx > 0) {
mOptionalValues.GetNodeAssignmentFor(this, binding, idx,
getter_AddRefs(node));
}
}
}
*aValue = node;
NS_IF_ADDREF(*aValue);
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::RuleMatched(nsISupports* aQueryNode,
nsIDOMNode* aRuleNode)
{
// when a rule matches, set the bindings that must be used.
nsXULTemplateQueryProcessorXML* processor = mQuery ? mQuery->Processor() :
nsnull;
if (processor) {
nsXMLBindingSet* bindings =
processor->GetOptionalBindingsForRule(aRuleNode);
if (bindings)
mOptionalValues.SetBindingSet(bindings);
}
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateResultXML::HasBeenRemoved()
{
return NS_OK;
}
void
nsXULTemplateResultXML::GetNode(nsIDOMNode** aNode)
{
*aNode = mNode;
NS_IF_ADDREF(*aNode);
}

Просмотреть файл

@ -0,0 +1,81 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Neil Deakin
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsXULTemplateResultXML_h__
#define nsXULTemplateResultXML_h__
#include "nsCOMPtr.h"
#include "nsIRDFResource.h"
#include "nsXULTemplateQueryProcessorXML.h"
#include "nsIXULTemplateResult.h"
/**
* An single result of an query
*/
class nsXULTemplateResultXML : public nsIXULTemplateResult
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIXULTEMPLATERESULT
nsXULTemplateResultXML(nsXMLQuery* aQuery,
nsIDOMNode* aNode,
nsXMLBindingSet* aBindings);
~nsXULTemplateResultXML() {}
void GetNode(nsIDOMNode** aNode);
protected:
// result id
PRUint32 mId;
// query that generated the result
nsCOMPtr<nsXMLQuery> mQuery;
// context node in datasource
nsCOMPtr<nsIDOMNode> mNode;
// assignments in query
nsXMLBindingValues mRequiredValues;
// extra assignments made by rules (<binding> tags)
nsXMLBindingValues mOptionalValues;
};
#endif // nsXULTemplateResultXML_h__

Просмотреть файл

@ -1374,7 +1374,8 @@ nsXULTreeBuilder::RebuildAll()
mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::ref, ref);
if (! ref.IsEmpty()) {
rv = mQueryProcessor->TranslateRef(mDB, ref, getter_AddRefs(mRootResult));
rv = mQueryProcessor->TranslateRef(mDataSource, ref,
getter_AddRefs(mRootResult));
if (NS_FAILED(rv))
return rv;
@ -1577,7 +1578,7 @@ nsXULTreeBuilder::OpenSubtreeForQuerySet(nsTreeRows::Subtree* aSubtree,
PRInt32 count = *aDelta;
nsCOMPtr<nsISimpleEnumerator> results;
nsresult rv = mQueryProcessor->GenerateResults(mDB, aResult,
nsresult rv = mQueryProcessor->GenerateResults(mDataSource, aResult,
aQuerySet->mCompiledQuery,
getter_AddRefs(results));
if (NS_FAILED(rv))
@ -1812,7 +1813,9 @@ nsXULTreeBuilder::Compare(const void* aLeft, const void* aRight, void* aClosure)
PRInt32
nsXULTreeBuilder::CompareResults(nsIXULTemplateResult* aLeft, nsIXULTemplateResult* aRight)
{
if (mSortDirection == eDirection_Natural) {
// this is an extra check done for RDF queries such that results appear in
// the order they appear in their containing Seq
if (mSortDirection == eDirection_Natural && mDB) {
// If the sort order is ``natural'', then see if the container
// is an RDF sequence. If so, we'll try to use the ordinal
// properties to determine order.