diff --git a/content/xslt/src/xslt/txKey.h b/content/xslt/src/xslt/txKey.h new file mode 100644 index 000000000000..2945db527393 --- /dev/null +++ b/content/xslt/src/xslt/txKey.h @@ -0,0 +1,216 @@ +/* -*- 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 TransforMiiX XSLT processor. + * + * The Initial Developer of the Original Code is + * Jonas Sicking. + * Portions created by the Initial Developer are Copyright (C) 2003 + * Jonas Sicking. All Rights Reserved. + * + * Contributor(s): + * Jonas Sicking + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 txKey_h__ +#define txKey_h__ + +#include "nsDoubleHashTable.h" +#include "XMLUtils.h" + +class txKeyValueHashKey +{ +public: + txKeyValueHashKey(const txExpandedName& aKeyName, + Document* aDocument, + const nsAString& aKeyValue) + : mKeyName(aKeyName), + mKeyValue(aKeyValue), + mDocument(aDocument) + { + } + + txExpandedName mKeyName; + nsString mKeyValue; + Document* mDocument; +}; + +struct txKeyValueHashEntry : public PLDHashEntryHdr +{ + txKeyValueHashEntry(const void* aKey) + : mKey(*NS_STATIC_CAST(const txKeyValueHashKey*, aKey)) + { + } + + // @see nsDoubleHashtable.h + const void* GetKey(); + PRBool MatchEntry(const void* aKey) const; + static PLDHashNumber HashKey(const void* aKey); + + txKeyValueHashKey mKey; + NodeSet mNodeSet; +}; + +DECL_DHASH_WRAPPER(txKeyValueHash, txKeyValueHashEntry, txKeyValueHashKey&); + +class txIndexedKeyHashKey +{ +public: + txIndexedKeyHashKey(txExpandedName aKeyName, + Document* aDocument) + : mKeyName(aKeyName), + mDocument(aDocument) + { + } + + txExpandedName mKeyName; + Document* mDocument; +}; + +struct txIndexedKeyHashEntry : public PLDHashEntryHdr +{ + txIndexedKeyHashEntry(const void* aKey) + : mKey(*NS_STATIC_CAST(const txIndexedKeyHashKey*, aKey)), + mIndexed(PR_FALSE) + { + } + + // @see nsDoubleHashtable.h + const void* GetKey(); + PRBool MatchEntry(const void* aKey) const; + static PLDHashNumber HashKey(const void* aKey); + + txIndexedKeyHashKey mKey; + PRBool mIndexed; +}; + +DECL_DHASH_WRAPPER(txIndexedKeyHash, txIndexedKeyHashEntry, + txIndexedKeyHashKey&); + +/** + * Class holding all s of a particular expanded name in the + * stylesheet. + */ +class txXSLKey : public TxObject { + +public: + txXSLKey(const txExpandedName& aName) : mName(aName) + { + } + ~txXSLKey(); + + /** + * Adds a match/use pair. + * @param aMatch match-pattern + * @param aUse use-expression + * @return PR_FALSE if an error occured, PR_TRUE otherwise + */ + PRBool addKey(txPattern* aMatch, Expr* aUse); + + /** + * Indexes a document and adds it to the hash of key values + * @param aDocument Document to index and add + * @param aKeyValueHash Hash to add values to + * @param aPs ProcessorState to use for XPath evaluation + */ + nsresult indexDocument(Document* aDocument, + txKeyValueHash& aKeyValueHash, + ProcessorState* aPs); + +private: + /** + * Recursively searches a node, its attributes and its subtree for + * nodes matching any of the keys match-patterns. + * @param aNode Node to search + * @param aKey Key to use when adding into the hash + * @param aKeyValueHash Hash to add values to + * @param aPs ProcessorState to use for XPath evaluation + */ + nsresult indexTree(Node* aNode, txKeyValueHashKey& aKey, + txKeyValueHash& aKeyValueHash, ProcessorState* aPs); + + /** + * Tests one node if it matches any of the keys match-patterns. If + * the node matches its values are added to the index. + * @param aNode Node to test + * @param aKey Key to use when adding into the hash + * @param aKeyValueHash Hash to add values to + * @param aPs ProcessorState to use for XPath evaluation + */ + nsresult testNode(Node* aNode, txKeyValueHashKey& aKey, + txKeyValueHash& aKeyValueHash, ProcessorState* aPs); + + /** + * represents one match/use pair + */ + struct Key { + txPattern* matchPattern; + Expr* useExpr; + }; + + /** + * List of all match/use pairs. The items as |Key|s + */ + List mKeys; + + /** + * Name of this key + */ + txExpandedName mName; +}; + + +class txKeyHash +{ +public: + txKeyHash(txExpandedNameMap& aKeys) + : mKeys(aKeys) + { + } + + nsresult init(); + + nsresult getKeyNodes(const txExpandedName& aKeyName, + Document* aDocument, + const nsAString& aKeyValue, + PRBool aIndexIfNotFound, + ProcessorState* aPs, + const NodeSet** aResult); + +private: + // Hash of all indexed key-values + txKeyValueHash mKeyValues; + + // Hash showing which keys+documents has been indexed + txIndexedKeyHash mIndexedKeys; + + // Map of txXSLKeys + txExpandedNameMap& mKeys; +}; + + +#endif //txKey_h__ diff --git a/content/xslt/src/xslt/txKeyFunctionCall.cpp b/content/xslt/src/xslt/txKeyFunctionCall.cpp index 6134a40b7e4e..c2c36e16f5cf 100644 --- a/content/xslt/src/xslt/txKeyFunctionCall.cpp +++ b/content/xslt/src/xslt/txKeyFunctionCall.cpp @@ -24,6 +24,8 @@ #include "txSingleNodeContext.h" #include "XMLDOMUtils.h" #include "XSLTFunctions.h" +#include "nsReadableUtils.h" +#include "txKey.h" /* * txKeyFunctionCall @@ -62,23 +64,16 @@ ExprResult* txKeyFunctionCall::evaluate(txIEvalContext* aContext) txListIterator iter(¶ms); nsAutoString keyQName; evaluateToString((Expr*)iter.next(), aContext, keyQName); - Expr* param = (Expr*) iter.next(); txExpandedName keyName; txXSLKey* key = 0; - nsresult rv = keyName.init(keyQName, mQNameResolveNode, MB_FALSE); - if (NS_SUCCEEDED(rv)) { - key = mProcessorState->getKey(keyName); + nsresult rv = keyName.init(keyQName, mQNameResolveNode, PR_FALSE); + if (NS_FAILED(rv)) { + delete res; + return new StringResult(NS_LITERAL_STRING("error")); } - if (!key) { - nsAutoString err(NS_LITERAL_STRING("No key with that name in: ")); - toString(err); - aContext->receiveError(err, NS_ERROR_INVALID_ARG); - return res; - } - - ExprResult* exprResult = param->evaluate(aContext); + ExprResult* exprResult = ((Expr*)iter.next())->evaluate(aContext); if (!exprResult) return res; @@ -91,21 +86,41 @@ ExprResult* txKeyFunctionCall::evaluate(txIEvalContext* aContext) if (exprResult->getResultType() == ExprResult::NODESET) { NodeSet* nodeSet = (NodeSet*) exprResult; - for (int i=0; isize(); i++) { + int i; + for (i = 0; i < nodeSet->size(); ++i) { nsAutoString val; XMLDOMUtils::getNodeValue(nodeSet->get(i), val); - res->add(key->getNodes(val, contextDoc)); + const NodeSet* nodes = 0; + rv = mProcessorState->getKeyNodes(keyName, contextDoc, val, + i == 0, &nodes); + if (NS_FAILED(rv)) { + delete res; + delete exprResult; + return new StringResult(NS_LITERAL_STRING("error")); + } + if (nodes) { + res->add(nodes); + } } } else { nsAutoString val; exprResult->stringValue(val); - res->append(key->getNodes(val, contextDoc)); + const NodeSet* nodes = 0; + rv = mProcessorState->getKeyNodes(keyName, contextDoc, val, + PR_TRUE, &nodes); + if (NS_FAILED(rv)) { + delete res; + delete exprResult; + return new StringResult(NS_LITERAL_STRING("error")); + } + if (nodes) { + res->append(nodes); + } } delete exprResult; return res; - -} // evaluate +} nsresult txKeyFunctionCall::getNameAtom(nsIAtom** aAtom) { @@ -114,17 +129,148 @@ nsresult txKeyFunctionCall::getNameAtom(nsIAtom** aAtom) return NS_OK; } -/* - * Class representing an . Or in the case where several s - * have the same name one object represents all s with that name +/** + * Hash functions */ -txXSLKey::txXSLKey(ProcessorState* aPs) -{ - mProcessorState = aPs; - mMaps.setOwnership(Map::eOwnsItems); -} // txXSLKey +DHASH_WRAPPER(txKeyValueHash, txKeyValueHashEntry, txKeyValueHashKey&); +DHASH_WRAPPER(txIndexedKeyHash, txIndexedKeyHashEntry, txIndexedKeyHashKey&); +const void* +txKeyValueHashEntry::GetKey() +{ + return &mKey; +} + +PRBool +txKeyValueHashEntry::MatchEntry(const void* aKey) const +{ + const txKeyValueHashKey* key = + NS_STATIC_CAST(const txKeyValueHashKey*, aKey); + + return mKey.mKeyName == key->mKeyName && + mKey.mDocument == key->mDocument && + mKey.mKeyValue.Equals(key->mKeyValue); +} + +PLDHashNumber +txKeyValueHashEntry::HashKey(const void* aKey) +{ + const txKeyValueHashKey* key = + NS_STATIC_CAST(const txKeyValueHashKey*, aKey); + + return key->mKeyName.mNamespaceID ^ + NS_PTR_TO_INT32(key->mKeyName.mLocalName.get()) ^ + NS_PTR_TO_INT32(key->mDocument) ^ + HashString(key->mKeyValue); +} + +const void* +txIndexedKeyHashEntry::GetKey() +{ + return &mKey; +} + +PRBool +txIndexedKeyHashEntry::MatchEntry(const void* aKey) const +{ + const txIndexedKeyHashKey* key = + NS_STATIC_CAST(const txIndexedKeyHashKey*, aKey); + + return mKey.mKeyName == key->mKeyName && + mKey.mDocument == key->mDocument; +} + +PLDHashNumber +txIndexedKeyHashEntry::HashKey(const void* aKey) +{ + const txIndexedKeyHashKey* key = + NS_STATIC_CAST(const txIndexedKeyHashKey*, aKey); + + return key->mKeyName.mNamespaceID ^ + NS_PTR_TO_INT32(key->mKeyName.mLocalName.get()) ^ + NS_PTR_TO_INT32(key->mDocument); +} + +/* + * Class managing XSLT-keys + */ + +nsresult +txKeyHash::getKeyNodes(const txExpandedName& aKeyName, + Document* aDocument, + const nsAString& aKeyValue, + PRBool aIndexIfNotFound, + ProcessorState* aPs, + const NodeSet** aResult) +{ + NS_ENSURE_TRUE(mKeyValues.mHashTable.ops && mIndexedKeys.mHashTable.ops, + NS_ERROR_OUT_OF_MEMORY); + + *aResult = nsnull; + txKeyValueHashKey valueKey(aKeyName, aDocument, aKeyValue); + txKeyValueHashEntry* valueEntry = mKeyValues.GetEntry(valueKey); + if (valueEntry) { + *aResult = &valueEntry->mNodeSet; + return NS_OK; + } + + // We didn't find a value. This could either mean that that key has no + // nodes with that value or that the key hasn't been indexed using this + // document. + + if (!aIndexIfNotFound) { + // If aIndexIfNotFound is set then the caller knows this key is + // indexed, so don't bother investigating. + return NS_OK; + } + + txIndexedKeyHashKey indexKey(aKeyName, aDocument); + txIndexedKeyHashEntry* indexEntry = mIndexedKeys.AddEntry(indexKey); + NS_ENSURE_TRUE(indexEntry, NS_ERROR_OUT_OF_MEMORY); + + if (indexEntry->mIndexed) { + // The key was indexed and apparently didn't contain this value so + // return null. + + return NS_OK; + } + + // The key needs to be indexed. + txXSLKey* xslKey = (txXSLKey*)mKeys.get(aKeyName); + if (!xslKey) { + // The key didn't exist, so bail. + return NS_ERROR_INVALID_ARG; + } + + nsresult rv = xslKey->indexDocument(aDocument, mKeyValues, aPs); + NS_ENSURE_SUCCESS(rv, rv); + + indexEntry->mIndexed = PR_TRUE; + + // Now that the key is indexed we can get its value. + valueEntry = mKeyValues.GetEntry(valueKey); + if (valueEntry) { + *aResult = &valueEntry->mNodeSet; + } + + return NS_OK; +} + +nsresult +txKeyHash::init() +{ + nsresult rv = mKeyValues.Init(8); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mIndexedKeys.Init(1); + NS_ENSURE_SUCCESS(rv, rv); +} + +/** + * Class holding all s of a particular expanded name in the + * stylesheet. + */ txXSLKey::~txXSLKey() { txListIterator iter(&mKeys); @@ -134,150 +280,133 @@ txXSLKey::~txXSLKey() delete key->useExpr; delete key; } -} // ~txXSLKey +} -/* - * Returns a NodeSet containing all nodes within the specified document - * that have the value keyValue. The document is indexed in case it - * hasn't been searched previously. The returned nodeset is owned by - * the txXSLKey object - * @param aKeyValue Value to search for - * @param aDoc Document to search in - * @return a NodeSet* containing all nodes in doc matching with value - * keyValue - */ -const NodeSet* txXSLKey::getNodes(const nsAString& aKeyValue, Document* aDoc) -{ - NS_ASSERTION(aDoc, "missing document"); - if (!aDoc) - return &mEmptyNodeset; - - NamedMap* map = (NamedMap*)mMaps.get(aDoc); - if (!map) { - map = addDocument(aDoc); - if (!map) - return &mEmptyNodeset; - } - - NodeSet* nodes = (NodeSet*)map->get(aKeyValue); - if (!nodes) - return &mEmptyNodeset; - - return nodes; -} // getNodes - -/* - * Adds a match/use pair. Returns MB_FALSE if matchString or useString - * can't be parsed. +/** + * Adds a match/use pair. * @param aMatch match-pattern * @param aUse use-expression - * @return MB_FALSE if an error occured, MB_TRUE otherwise + * @return PR_FALSE if an error occured, PR_TRUE otherwise */ -MBool txXSLKey::addKey(txPattern* aMatch, Expr* aUse) +PRBool txXSLKey::addKey(txPattern* aMatch, Expr* aUse) { if (!aMatch || !aUse) - return MB_FALSE; + return PR_FALSE; Key* key = new Key; if (!key) - return MB_FALSE; + return PR_FALSE; key->matchPattern = aMatch; key->useExpr = aUse; mKeys.add(key); - return MB_TRUE; -} // addKey + return PR_TRUE; +} -/* - * Indexes a document and adds it to the set of indexed documents - * @param aDoc Document to index and add - * @returns a NamedMap* containing the index +/** + * Indexes a document and adds it to the hash of key values + * @param aDocument Document to index and add + * @param aKeyValueHash Hash to add values to + * @param aPs ProcessorState to use for XPath evaluation */ -NamedMap* txXSLKey::addDocument(Document* aDoc) +nsresult txXSLKey::indexDocument(Document* aDocument, + txKeyValueHash& aKeyValueHash, + ProcessorState* aPs) { - NamedMap* map = new NamedMap; - if (!map) - return nsnull; - map->setObjectDeletion(MB_TRUE); - mMaps.put(aDoc, map); - indexTree(aDoc, map); - return map; -} // addDocument + txKeyValueHashKey key(mName, aDocument, NS_LITERAL_STRING("")); + return indexTree(aDocument, key, aKeyValueHash, aPs); +} -/* +/** * Recursively searches a node, its attributes and its subtree for * nodes matching any of the keys match-patterns. - * @param aNode node to search - * @param aMap index to add search result in + * @param aNode Node to search + * @param aKey Key to use when adding into the hash + * @param aKeyValueHash Hash to add values to + * @param aPs ProcessorState to use for XPath evaluation */ -void txXSLKey::indexTree(Node* aNode, NamedMap* aMap) +nsresult txXSLKey::indexTree(Node* aNode, txKeyValueHashKey& aKey, + txKeyValueHash& aKeyValueHash, + ProcessorState* aPs) { - testNode(aNode, aMap); + nsresult rv = testNode(aNode, aKey, aKeyValueHash, aPs); + NS_ENSURE_SUCCESS(rv, rv); // check if the nodes attributes matches NamedNodeMap* attrs = aNode->getAttributes(); if (attrs) { for (PRUint32 i=0; igetLength(); i++) { - testNode(attrs->item(i), aMap); + rv = testNode(attrs->item(i), aKey, aKeyValueHash, aPs); + NS_ENSURE_SUCCESS(rv, rv); } } Node* child = aNode->getFirstChild(); while (child) { - indexTree(child, aMap); + rv = indexTree(child, aKey, aKeyValueHash, aPs); + NS_ENSURE_SUCCESS(rv, rv); + child = child->getNextSibling(); } -} // indexTree + + return NS_OK; +} -/* +/** * Tests one node if it matches any of the keys match-patterns. If * the node matches its values are added to the index. - * @param aNode node to test - * @param aMap index to add values to + * @param aNode Node to test + * @param aKey Key to use when adding into the hash + * @param aKeyValueHash Hash to add values to + * @param aPs ProcessorState to use for XPath evaluation */ -void txXSLKey::testNode(Node* aNode, NamedMap* aMap) +nsresult txXSLKey::testNode(Node* aNode, txKeyValueHashKey& aKey, + txKeyValueHash& aKeyValueHash, ProcessorState* aPs) { nsAutoString val; - NodeSet *nodeSet; - txListIterator iter(&mKeys); while (iter.hasNext()) { Key* key=(Key*)iter.next(); - if (key->matchPattern->matches(aNode, mProcessorState)) { - txSingleNodeContext evalContext(aNode, mProcessorState); + if (key->matchPattern->matches(aNode, aPs)) { + txSingleNodeContext evalContext(aNode, aPs); txIEvalContext* prevCon = - mProcessorState->setEvalContext(&evalContext); + aPs->setEvalContext(&evalContext); ExprResult* exprResult = key->useExpr->evaluate(&evalContext); - mProcessorState->setEvalContext(prevCon); + aPs->setEvalContext(prevCon); if (exprResult->getResultType() == ExprResult::NODESET) { NodeSet* res = (NodeSet*)exprResult; for (int i=0; isize(); i++) { val.Truncate(); XMLDOMUtils::getNodeValue(res->get(i), val); - nodeSet = (NodeSet*)aMap->get(val); - if (!nodeSet) { - nodeSet = new NodeSet; - if (!nodeSet) - return; - aMap->put(val, nodeSet); + aKey.mKeyValue.Assign(val); + txKeyValueHashEntry* entry = aKeyValueHash.AddEntry(aKey); + NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY); + + if (entry->mNodeSet.isEmpty() || + entry->mNodeSet.get(entry->mNodeSet.size() - 1) != + aNode) { + entry->mNodeSet.append(aNode); } - nodeSet->append(aNode); } } else { exprResult->stringValue(val); - nodeSet = (NodeSet*)aMap->get(val); - if (!nodeSet) { - nodeSet = new NodeSet; - if (!nodeSet) - return; - aMap->put(val, nodeSet); + + aKey.mKeyValue.Assign(val); + txKeyValueHashEntry* entry = aKeyValueHash.AddEntry(aKey); + NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY); + + if (entry->mNodeSet.isEmpty() || + entry->mNodeSet.get(entry->mNodeSet.size()-1) != + aNode) { + entry->mNodeSet.append(aNode); } - nodeSet->append(aNode); } delete exprResult; } } -} // testNode + + return NS_OK; +} diff --git a/content/xslt/src/xslt/txXSLTFunctions.h b/content/xslt/src/xslt/txXSLTFunctions.h index 54f92722a922..3ac1e1340c8d 100644 --- a/content/xslt/src/xslt/txXSLTFunctions.h +++ b/content/xslt/src/xslt/txXSLTFunctions.h @@ -35,9 +35,7 @@ #include "Map.h" #include "NodeSet.h" -class NamedMap; class ProcessorState; -class txPattern; /** * The definition for the XSLT document() function @@ -77,93 +75,6 @@ private: Node* mQNameResolveNode; }; -/* - * Class representing an . Or in the case where several s - * have the same name one object represents all s with that name - */ -class txXSLKey : public TxObject { - -public: - txXSLKey(ProcessorState* aPs); - ~txXSLKey(); - - /* - * Returns a NodeSet containing all nodes within the specified document - * that have the value keyValue. The document is indexed in case it - * hasn't been searched previously. The returned nodeset is owned by - * the txXSLKey object - * @param aKeyValue Value to search for - * @param aDoc Document to search in - * @return a NodeSet* containing all nodes in doc matching with value - * keyValue - */ - const NodeSet* getNodes(const nsAString& aKeyValue, Document* aDoc); - - /* - * Adds a match/use pair. Returns MB_FALSE if matchString or useString - * can't be parsed. - * @param aMatch match-pattern - * @param aUse use-expression - * @return MB_FALSE if an error occured, MB_TRUE otherwise - */ - MBool addKey(txPattern* aMatch, Expr* aUse); - -private: - /* - * Indexes a document and adds it to the set of indexed documents - * @param aDoc Document to index and add - * @returns a NamedMap* containing the index - */ - NamedMap* addDocument(Document* aDoc); - - /* - * Recursively searches a node, its attributes and its subtree for - * nodes matching any of the keys match-patterns. - * @param aNode node to search - * @param aMap index to add search result in - */ - void indexTree(Node* aNode, NamedMap* aMap); - - /* - * Tests one node if it matches any of the keys match-patterns. If - * the node matches its values are added to the index. - * @param aNode node to test - * @param aMap index to add values to - */ - void testNode(Node* aNode, NamedMap* aMap); - - /* - * represents one match/use pair - */ - struct Key { - txPattern* matchPattern; - Expr* useExpr; - }; - - /* - * List of all match/use pairs - */ - List mKeys; - - /* - * Map containing all indexes (keyed on document). Every index is a - * NamedMap. Every NamedMap contains NodeLists with the nodes for - * a certain value - */ - Map mMaps; - - /* - * ProcessorState used to parse the match-patterns and - * use-expressions - */ - ProcessorState* mProcessorState; - - /* - * Used to return empty nodeset - */ - NodeSet mEmptyNodeset; -}; - /** * The definition for the XSLT format-number() function **/ diff --git a/content/xslt/src/xslt/txXSLTPatterns.cpp b/content/xslt/src/xslt/txXSLTPatterns.cpp index bf6f1ff90b03..0d1d58dbca82 100644 --- a/content/xslt/src/xslt/txXSLTPatterns.cpp +++ b/content/xslt/src/xslt/txXSLTPatterns.cpp @@ -435,9 +435,10 @@ MBool txKeyPattern::matches(Node* aNode, txIMatchContext* aContext) contextDoc = (Document*)aNode; else contextDoc = aNode->getOwnerDocument(); - txXSLKey* key = mProcessorState->getKey(mName); - const NodeSet* nodes = key->getNodes(mValue, contextDoc); - if (!nodes || nodes->isEmpty()) + const NodeSet* nodes = 0; + nsresult rv = mProcessorState->getKeyNodes(mName, contextDoc, mValue, + PR_TRUE, &nodes); + if (NS_FAILED(rv) || !nodes || nodes->isEmpty()) return MB_FALSE; MBool isTrue = nodes->contains(aNode); return isTrue;