зеркало из https://github.com/mozilla/pjs.git
Bug 187610: Use PLDHash for keys
r=Pike sr=peterv
This commit is contained in:
Родитель
19aa6e8368
Коммит
7b8177be9d
|
@ -129,6 +129,7 @@ ProcessorState::ProcessorState(Node* aSourceNode, Document* aXslDocument)
|
|||
mResultHandler(0),
|
||||
mOutputHandlerFactory(0),
|
||||
mXslKeys(MB_TRUE),
|
||||
mKeyHash(mXslKeys),
|
||||
mDecimalFormats(MB_TRUE),
|
||||
mEvalContext(0),
|
||||
mLocalVariables(0),
|
||||
|
@ -154,6 +155,8 @@ ProcessorState::ProcessorState(Node* aSourceNode, Document* aXslDocument)
|
|||
mExprHashes[ValueAttr].setOwnership(Map::eOwnsItems);
|
||||
mPatternHashes[CountAttr].setOwnership(Map::eOwnsItems);
|
||||
mPatternHashes[FromAttr].setOwnership(Map::eOwnsItems);
|
||||
|
||||
mKeyHash.init();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -853,7 +856,7 @@ MBool ProcessorState::addKey(Element* aKeyElem)
|
|||
|
||||
txXSLKey* xslKey = (txXSLKey*)mXslKeys.get(keyName);
|
||||
if (!xslKey) {
|
||||
xslKey = new txXSLKey(this);
|
||||
xslKey = new txXSLKey(keyName);
|
||||
if (!xslKey)
|
||||
return MB_FALSE;
|
||||
rv = mXslKeys.add(keyName, xslKey);
|
||||
|
@ -879,15 +882,6 @@ MBool ProcessorState::addKey(Element* aKeyElem)
|
|||
return MB_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the supplied xsl:key to the set of keys
|
||||
* returns NULL if no such key exists
|
||||
**/
|
||||
txXSLKey* ProcessorState::getKey(txExpandedName& keyName)
|
||||
{
|
||||
return (txXSLKey*)mXslKeys.get(keyName);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds a decimal format. Returns false if the format already exists
|
||||
* but dosn't contain the exact same parametervalues
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "txError.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsDoubleHashtable.h"
|
||||
#include "txKey.h"
|
||||
|
||||
class txVariableMap;
|
||||
class txXSLKey;
|
||||
|
@ -308,10 +309,27 @@ public:
|
|||
MBool addKey(Element* aKeyElem);
|
||||
|
||||
/**
|
||||
* Returns the key with the supplied name
|
||||
* returns NULL if no such key exists
|
||||
* Get the nodeset for a key+document+value. Note that the result can
|
||||
* only be used until the next call to this function.
|
||||
* @param aKeyName Name of key.
|
||||
* @param aDocument Context-document to get key-nodes in.
|
||||
* @param aKeyValue Key-value to get the nodes for.
|
||||
* @param aIndexIfNotFound Check if the requested key is index in the
|
||||
* requested document and if it isn't index it.
|
||||
* This should only be false if it's known that
|
||||
* the key is already indexed in that document.
|
||||
* @param aResult Out-param returning the result. This pointer
|
||||
* can only be used until the next call to
|
||||
* getKeyNodes.
|
||||
*/
|
||||
txXSLKey* getKey(txExpandedName& keyName);
|
||||
nsresult getKeyNodes(const txExpandedName& aKeyName, Document* aDocument,
|
||||
const nsAString& aKeyValue, PRBool aIndexIfNotFound,
|
||||
const NodeSet** aResult)
|
||||
{
|
||||
return mKeyHash.getKeyNodes(aKeyName, aDocument, aKeyValue,
|
||||
aIndexIfNotFound, this, aResult);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a decimal format. Returns false if the format already exists
|
||||
|
@ -451,6 +469,11 @@ private:
|
|||
*/
|
||||
txExpandedNameMap mXslKeys;
|
||||
|
||||
/**
|
||||
* Hash of all key-values
|
||||
*/
|
||||
txKeyHash mKeyHash;
|
||||
|
||||
/**
|
||||
* The set of all avalible decimalformats
|
||||
*/
|
||||
|
|
|
@ -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 <xsl:key>. Or in the case where several <xsl:key>s
|
||||
* have the same name one object represents all <xsl:key>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
|
||||
**/
|
||||
|
|
|
@ -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 <jonas@sicking.cc>
|
||||
*
|
||||
* 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 <xsl:key>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__
|
|
@ -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; i<nodeSet->size(); 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 <xsl:key>. Or in the case where several <xsl:key>s
|
||||
* have the same name one object represents all <xsl:key>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 <xsl:key>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; i<attrs->getLength(); 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; i<res->size(); 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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче