зеркало из https://github.com/mozilla/gecko-dev.git
Fix for bug 151002 (abstract the content by a treewalker). Patch by me, with parts by Pike and sicking. r=sicking, sr=jst.
This commit is contained in:
Родитель
df1d9c27bb
Коммит
6bb7249e06
|
@ -37,6 +37,7 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "txExpandedNameMap.h"
|
||||
#include "TxObject.h"
|
||||
#include <string.h>
|
||||
|
||||
const int kTxExpandedNameMapAllocSize = 16;
|
||||
|
|
|
@ -37,8 +37,8 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "txNamespaceMap.h"
|
||||
#include "dom.h"
|
||||
#include "txAtoms.h"
|
||||
#include "txXPathNode.h"
|
||||
|
||||
txNamespaceMap::txNamespaceMap()
|
||||
{
|
||||
|
|
|
@ -82,7 +82,7 @@ public:
|
|||
{
|
||||
if (!mXML || !mStylesheet || !mOut)
|
||||
return 1;
|
||||
nsresult rv = transform(mXML, mStylesheet, *mOut, mObserver);
|
||||
nsresult rv = transform(*mXML, mStylesheet, *mOut, mObserver);
|
||||
return NS_FAILED(rv);
|
||||
}
|
||||
int closeOutput ()
|
||||
|
@ -110,7 +110,7 @@ public:
|
|||
delete mOut;
|
||||
}
|
||||
private:
|
||||
Document *mXML;
|
||||
txXPathNode *mXML;
|
||||
nsRefPtr<txStylesheet> mStylesheet;
|
||||
SimpleErrorObserver mObserver;
|
||||
ofstream* mOut;
|
||||
|
|
|
@ -35,12 +35,13 @@ REQUIRES += dom \
|
|||
content \
|
||||
widget \
|
||||
unicharutil \
|
||||
necko \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
DIRS = dom parser
|
||||
|
||||
CPPSRCS = XMLDOMUtils.cpp XMLUtils.cpp
|
||||
CPPSRCS = XMLUtils.cpp
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
|
|
@ -149,6 +149,7 @@ class NodeList
|
|||
class NodeListDefinition : public NodeList
|
||||
{
|
||||
friend class NamedNodeMap; //-- LF
|
||||
friend class txXPathTreeWalker;
|
||||
public:
|
||||
NodeListDefinition();
|
||||
virtual ~NodeListDefinition();
|
||||
|
@ -188,6 +189,8 @@ class NamedNodeMap : public NodeListDefinition
|
|||
|
||||
private:
|
||||
NodeListDefinition::ListItem* findListItemByName(const nsAString& name);
|
||||
// txXPathTreeWalker is friend to speed up attr iterations
|
||||
friend class txXPathTreeWalker;
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -268,6 +271,8 @@ class NodeDefinition : public Node, public NodeList
|
|||
|
||||
protected:
|
||||
friend class Document;
|
||||
friend class txXPathTreeWalker;
|
||||
friend class txXPathNodeUtils;
|
||||
NodeDefinition(NodeType type, const nsAString& name,
|
||||
const nsAString& value, Document* owner);
|
||||
NodeDefinition(NodeType aType, const nsAString& aValue,
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include "txXMLParser.h"
|
||||
#include "txURIUtils.h"
|
||||
#include "txXPathTreeWalker.h"
|
||||
|
||||
#ifndef TX_EXE
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
|
@ -42,7 +44,7 @@ class txXMLParser
|
|||
{
|
||||
public:
|
||||
nsresult parse(istream& aInputStream, const nsAString& aUri,
|
||||
Document** aResultDoc);
|
||||
txXPathNode** aResultDoc);
|
||||
const nsAString& getErrorString();
|
||||
|
||||
/**
|
||||
|
@ -68,8 +70,8 @@ class txXMLParser
|
|||
|
||||
nsresult
|
||||
txParseDocumentFromURI(const nsAString& aHref, const nsAString& aReferrer,
|
||||
Document* aLoader, nsAString& aErrMsg,
|
||||
Document** aResult)
|
||||
const txXPathNode& aLoader, nsAString& aErrMsg,
|
||||
txXPathNode** aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
*aResult = nsnull;
|
||||
|
@ -78,9 +80,8 @@ txParseDocumentFromURI(const nsAString& aHref, const nsAString& aReferrer,
|
|||
nsresult rv = NS_NewURI(getter_AddRefs(documentURI), aHref);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> theDocument;
|
||||
nsCOMPtr<nsIDocument> loaderDocument =
|
||||
do_QueryInterface(aLoader->getNSObj());
|
||||
nsIDocument* loaderDocument = txXPathNativeNode::getDocument(aLoader);
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = loaderDocument->GetDocumentLoadGroup();
|
||||
nsIURI *loaderUri = loaderDocument->GetDocumentURL();
|
||||
NS_ENSURE_TRUE(loaderUri, NS_ERROR_FAILURE);
|
||||
|
@ -97,7 +98,7 @@ txParseDocumentFromURI(const nsAString& aHref, const nsAString& aReferrer,
|
|||
if (refUri) {
|
||||
http->SetReferrer(refUri);
|
||||
}
|
||||
http->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
|
||||
http->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
|
||||
NS_LITERAL_CSTRING("text/xml,application/xml,application/xhtml+xml,*/*;q=0.1"),
|
||||
PR_FALSE);
|
||||
|
||||
|
@ -108,15 +109,19 @@ txParseDocumentFromURI(const nsAString& aHref, const nsAString& aReferrer,
|
|||
do_GetService("@mozilla.org/content/syncload-dom-service;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = loader->LoadDocumentAsXML(channel, loaderUri, getter_AddRefs(theDocument));
|
||||
// Raw pointer, we want the resulting txXPathNode to hold a reference to
|
||||
// the document.
|
||||
nsIDOMDocument* theDocument = nsnull;
|
||||
rv = loader->LoadDocumentAsXML(channel, loaderUri, &theDocument);
|
||||
if (NS_FAILED(rv) || !theDocument) {
|
||||
aErrMsg.Append(NS_LITERAL_STRING("Document load of ") +
|
||||
aHref + NS_LITERAL_STRING(" failed."));
|
||||
return rv;
|
||||
}
|
||||
|
||||
*aResult = new Document(theDocument);
|
||||
*aResult = txXPathNativeNode::createXPathNode(theDocument);
|
||||
if (!*aResult) {
|
||||
NS_RELEASE(theDocument);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -133,7 +138,7 @@ txParseDocumentFromURI(const nsAString& aHref, const nsAString& aReferrer,
|
|||
#ifdef TX_EXE
|
||||
nsresult
|
||||
txParseFromStream(istream& aInputStream, const nsAString& aUri,
|
||||
nsAString& aErrorString, Document** aResult)
|
||||
nsAString& aErrorString, txXPathNode** aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
txXMLParser parser;
|
||||
|
@ -211,7 +216,7 @@ externalEntityRefHandler(XML_Parser aParser,
|
|||
*/
|
||||
nsresult
|
||||
txXMLParser::parse(istream& aInputStream, const nsAString& aUri,
|
||||
Document** aResultDoc)
|
||||
txXPathNode** aResultDoc)
|
||||
{
|
||||
mErrorString.Truncate();
|
||||
*aResultDoc = nsnull;
|
||||
|
@ -263,9 +268,9 @@ txXMLParser::parse(istream& aInputStream, const nsAString& aUri,
|
|||
// clean up
|
||||
XML_ParserFree(mExpatParser);
|
||||
// ownership to the caller
|
||||
*aResultDoc = mDocument;
|
||||
*aResultDoc = txXPathNativeNode::createXPathNode(mDocument);
|
||||
mDocument = nsnull;
|
||||
return NS_OK;
|
||||
return *aResultDoc ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
const nsAString&
|
||||
|
|
|
@ -25,12 +25,15 @@
|
|||
#ifndef MITRE_XMLPARSER_H
|
||||
#define MITRE_XMLPARSER_H
|
||||
|
||||
#include "dom.h"
|
||||
#include "baseutils.h"
|
||||
|
||||
#ifdef TX_EXE
|
||||
#include <iostream.h>
|
||||
#endif
|
||||
|
||||
class nsAString;
|
||||
class txXPathNode;
|
||||
|
||||
/**
|
||||
* API to load XML files into DOM datastructures.
|
||||
* Parsing is either done by expat, or by expat via the synchloaderservice
|
||||
|
@ -42,8 +45,8 @@
|
|||
*/
|
||||
extern "C" nsresult
|
||||
txParseDocumentFromURI(const nsAString& aHref, const nsAString& aReferrer,
|
||||
Document* aLoader, nsAString& aErrMsg,
|
||||
Document** aResult);
|
||||
const txXPathNode& aLoader, nsAString& aErrMsg,
|
||||
txXPathNode** aResult);
|
||||
|
||||
#ifdef TX_EXE
|
||||
/**
|
||||
|
@ -51,6 +54,6 @@ txParseDocumentFromURI(const nsAString& aHref, const nsAString& aReferrer,
|
|||
*/
|
||||
extern "C" nsresult
|
||||
txParseFromStream(istream& aInputStream, const nsAString& aUri,
|
||||
nsAString& aErrorString, Document** aResult);
|
||||
nsAString& aErrorString, txXPathNode** aResult);
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "txAtoms.h"
|
||||
#include "txStringUtils.h"
|
||||
#include "txNamespaceMap.h"
|
||||
#include "txXPathTreeWalker.h"
|
||||
|
||||
/**
|
||||
* Helper class for checking and partioning of QNames
|
||||
|
@ -233,16 +234,6 @@ PRBool XMLUtils::isWhitespace(const nsAFlatString& aText)
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given node's value has only whitespace characters
|
||||
*/
|
||||
PRBool XMLUtils::isWhitespace(Node* aNode)
|
||||
{
|
||||
nsAutoString text;
|
||||
aNode->getNodeValue(text);
|
||||
return isWhitespace(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the value of a XML processing instruction
|
||||
**/
|
||||
|
@ -275,31 +266,21 @@ void XMLUtils::normalizePIValue(nsAString& piValue)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Walks up the document tree and returns true if the closest xml:space
|
||||
* attribute is "preserve"
|
||||
*/
|
||||
//static
|
||||
MBool XMLUtils::getXMLSpacePreserve(Node* aNode)
|
||||
MBool XMLUtils::getXMLSpacePreserve(const txXPathNode& aNode)
|
||||
{
|
||||
NS_ASSERTION(aNode, "Calling preserveXMLSpace with NULL node!");
|
||||
|
||||
nsAutoString value;
|
||||
Node* parent = aNode;
|
||||
while (parent) {
|
||||
if (parent->getNodeType() == Node::ELEMENT_NODE) {
|
||||
Element* elem = (Element*)parent;
|
||||
if (elem->getAttr(txXMLAtoms::space, kNameSpaceID_XML, value)) {
|
||||
if (TX_StringEqualsAtom(value, txXMLAtoms::preserve)) {
|
||||
return MB_TRUE;
|
||||
}
|
||||
if (TX_StringEqualsAtom(value, txXMLAtoms::_default)) {
|
||||
return MB_FALSE;
|
||||
}
|
||||
txXPathTreeWalker walker(aNode);
|
||||
do {
|
||||
if (walker.getAttr(txXMLAtoms::space, kNameSpaceID_XML, value)) {
|
||||
if (TX_StringEqualsAtom(value, txXMLAtoms::preserve)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
if (TX_StringEqualsAtom(value, txXMLAtoms::_default)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
parent = parent->getParentNode();
|
||||
}
|
||||
} while (walker.moveToParent());
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
|
|
@ -31,10 +31,10 @@
|
|||
#define MITRE_XMLUTILS_H
|
||||
|
||||
#include "baseutils.h"
|
||||
#include "dom.h"
|
||||
#include "nsDependentSubstring.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "txError.h"
|
||||
#include "txXPathNode.h"
|
||||
|
||||
class txNamespaceMap;
|
||||
|
||||
|
@ -126,12 +126,6 @@ public:
|
|||
*/
|
||||
static PRBool isWhitespace(const nsAFlatString& aText);
|
||||
|
||||
/**
|
||||
* Returns true if the given node's DOM nodevalue has only whitespace
|
||||
* characters
|
||||
*/
|
||||
static PRBool isWhitespace(Node* aNode);
|
||||
|
||||
/**
|
||||
* Normalizes the value of a XML processingInstruction
|
||||
**/
|
||||
|
@ -156,7 +150,7 @@ public:
|
|||
* Walks up the document tree and returns true if the closest xml:space
|
||||
* attribute is "preserve"
|
||||
*/
|
||||
static MBool getXMLSpacePreserve(Node* aNode);
|
||||
static MBool getXMLSpacePreserve(const txXPathNode& aNode);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -79,7 +79,10 @@ CPPSRCS += nsXPathEvaluator.cpp \
|
|||
nsXPathExpression.cpp \
|
||||
nsXPathNSResolver.cpp \
|
||||
nsXPathResult.cpp \
|
||||
nsXPath1Scheme.cpp
|
||||
nsXPath1Scheme.cpp \
|
||||
txMozillaXPathTreeWalker.cpp
|
||||
else
|
||||
CPPSRCS += txStandaloneXPathTreeWalker.cpp
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
#include "nsXPathResult.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "txURIUtils.h"
|
||||
|
||||
#include "txXPathTreeWalker.h"
|
||||
|
||||
NS_IMPL_ADDREF(nsXPathExpression)
|
||||
NS_IMPL_RELEASE(nsXPathExpression)
|
||||
|
@ -112,16 +112,12 @@ nsXPathExpression::Evaluate(nsIDOMNode *aContextNode,
|
|||
NS_ENSURE_ARG(aResult);
|
||||
*aResult = nsnull;
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> ownerDOMDocument;
|
||||
aContextNode->GetOwnerDocument(getter_AddRefs(ownerDOMDocument));
|
||||
if (!ownerDOMDocument) {
|
||||
ownerDOMDocument = do_QueryInterface(aContextNode);
|
||||
NS_ENSURE_TRUE(ownerDOMDocument, NS_ERROR_FAILURE);
|
||||
nsAutoPtr<txXPathNode> contextNode(txXPathNativeNode::createXPathNode(aContextNode));
|
||||
if (!contextNode) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
Document document(ownerDOMDocument);
|
||||
Node* node = document.createWrapper(aContextNode);
|
||||
|
||||
EvalContextImpl eContext(node, mRecycler);
|
||||
EvalContextImpl eContext(*contextNode, mRecycler);
|
||||
nsRefPtr<txAExprResult> exprResult;
|
||||
rv = mExpression->evaluate(&eContext, getter_AddRefs(exprResult));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -175,7 +171,7 @@ nsXPathExpression::EvalContextImpl::getVariable(PRInt32 aNamespace,
|
|||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
MBool nsXPathExpression::EvalContextImpl::isStripSpaceAllowed(Node* aNode)
|
||||
MBool nsXPathExpression::EvalContextImpl::isStripSpaceAllowed(const txXPathNode& aNode)
|
||||
{
|
||||
return MB_FALSE;
|
||||
}
|
||||
|
@ -198,7 +194,7 @@ void nsXPathExpression::EvalContextImpl::receiveError(const nsAString& aMsg,
|
|||
// forward aMsg to console service?
|
||||
}
|
||||
|
||||
Node* nsXPathExpression::EvalContextImpl::getContextNode()
|
||||
const txXPathNode& nsXPathExpression::EvalContextImpl::getContextNode()
|
||||
{
|
||||
return mContextNode;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "nsAutoPtr.h"
|
||||
|
||||
class Expr;
|
||||
class txXPathNode;
|
||||
|
||||
/**
|
||||
* A class for evaluating an XPath expression string
|
||||
|
@ -70,7 +71,7 @@ private:
|
|||
class EvalContextImpl : public txIEvalContext
|
||||
{
|
||||
public:
|
||||
EvalContextImpl(Node* aContextNode, txResultRecycler* aRecycler)
|
||||
EvalContextImpl(const txXPathNode& aContextNode, txResultRecycler* aRecycler)
|
||||
: mContextNode(aContextNode),
|
||||
mLastError(NS_OK),
|
||||
mRecycler(aRecycler)
|
||||
|
@ -89,7 +90,7 @@ private:
|
|||
TX_DECL_EVAL_CONTEXT;
|
||||
|
||||
private:
|
||||
Node* mContextNode;
|
||||
const txXPathNode& mContextNode;
|
||||
nsresult mLastError;
|
||||
nsRefPtr<txResultRecycler> mRecycler;
|
||||
};
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsXPathResult.h"
|
||||
#include "dom.h"
|
||||
#include "ExprResult.h"
|
||||
#include "txNodeSet.h"
|
||||
#include "nsDOMError.h"
|
||||
|
@ -292,9 +291,9 @@ nsXPathResult::SetExprResult(txAExprResult* aExprResult, PRUint16 aResultType)
|
|||
|
||||
if (mResultType == FIRST_ORDERED_NODE_TYPE ||
|
||||
mResultType == ANY_UNORDERED_NODE_TYPE) {
|
||||
Node* node = nodeSet->get(0);
|
||||
if (node)
|
||||
rv = CallQueryInterface(node->getNSObj(), &mNode);
|
||||
if (nodeSet->size() > 0) {
|
||||
txXPathNativeNode::getNode(nodeSet->get(0), &mNode);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (mResultType == UNORDERED_NODE_ITERATOR_TYPE ||
|
||||
|
@ -312,7 +311,7 @@ nsXPathResult::SetExprResult(txAExprResult* aExprResult, PRUint16 aResultType)
|
|||
nsCOMPtr<nsIDOMNode> node;
|
||||
PRInt32 i;
|
||||
for (i = 0; i < count; ++i) {
|
||||
node = do_QueryInterface(nodeSet->get(i)->getNSObj());
|
||||
txXPathNativeNode::getNode(nodeSet->get(i), getter_AddRefs(node));
|
||||
NS_ASSERTION(node, "node isn't an nsIDOMNode");
|
||||
mElements->AppendObject(node);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "txAtoms.h"
|
||||
#include "txIXPathContext.h"
|
||||
#include "txStringUtils.h"
|
||||
#include "txXPathTreeWalker.h"
|
||||
|
||||
/**
|
||||
* Creates a default BooleanFunctionCall, which always evaluates to False
|
||||
|
@ -71,27 +72,27 @@ BooleanFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
if (!requireParams(1, 1, aContext))
|
||||
return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
|
||||
|
||||
txXPathTreeWalker walker(aContext->getContextNode());
|
||||
|
||||
nsAutoString lang;
|
||||
Node* node = aContext->getContextNode();
|
||||
while (node) {
|
||||
if (node->getNodeType() == Node::ELEMENT_NODE) {
|
||||
Element* elem = (Element*)node;
|
||||
if (elem->getAttr(txXMLAtoms::lang,
|
||||
kNameSpaceID_XML, lang))
|
||||
break;
|
||||
}
|
||||
node = node->getParentNode();
|
||||
PRBool found;
|
||||
do {
|
||||
found = walker.getAttr(txXMLAtoms::lang, kNameSpaceID_XML,
|
||||
lang);
|
||||
} while (!found && walker.moveToParent());
|
||||
|
||||
if (!found) {
|
||||
aContext->recycler()->getBoolResult(PR_FALSE, aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MBool result = MB_FALSE;
|
||||
if (node) {
|
||||
nsAutoString arg;
|
||||
evaluateToString((Expr*)iter.next(), aContext, arg);
|
||||
result = arg.Equals(Substring(lang, 0, arg.Length()),
|
||||
txCaseInsensitiveStringComparator()) &&
|
||||
(lang.Length() == arg.Length() ||
|
||||
lang.CharAt(arg.Length()) == '-');
|
||||
}
|
||||
nsAutoString arg;
|
||||
evaluateToString((Expr*)iter.next(), aContext, arg);
|
||||
PRBool result = arg.Equals(Substring(lang, 0, arg.Length()),
|
||||
txCaseInsensitiveStringComparator()) &&
|
||||
(lang.Length() == arg.Length() ||
|
||||
lang.CharAt(arg.Length()) == '-');
|
||||
|
||||
aContext->recycler()->getBoolResult(result, aResult);
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
#define TRANSFRMX_EXPR_H
|
||||
|
||||
#include "baseutils.h"
|
||||
#include "dom.h"
|
||||
#include "List.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIAtom.h"
|
||||
|
@ -53,6 +52,7 @@ class txIParseContext;
|
|||
class txIMatchContext;
|
||||
class txIEvalContext;
|
||||
class txNodeSet;
|
||||
class txXPathNode;
|
||||
|
||||
/**
|
||||
* A Base Class for all XSL Expressions
|
||||
|
@ -212,13 +212,14 @@ public:
|
|||
* standalone. The NodeTest node() is different to the
|
||||
* Pattern "node()" (document node isn't matched)
|
||||
*/
|
||||
virtual MBool matches(Node* aNode, txIMatchContext* aContext) = 0;
|
||||
virtual PRBool matches(const txXPathNode& aNode,
|
||||
txIMatchContext* aContext) = 0;
|
||||
virtual double getDefaultPriority() = 0;
|
||||
virtual void toString(nsAString& aDest) = 0;
|
||||
};
|
||||
|
||||
#define TX_DECL_NODE_TEST \
|
||||
MBool matches(Node* aNode, txIMatchContext* aContext); \
|
||||
PRBool matches(const txXPathNode& aNode, txIMatchContext* aContext); \
|
||||
double getDefaultPriority(); \
|
||||
void toString(nsAString& aDest)
|
||||
|
||||
|
@ -233,7 +234,7 @@ public:
|
|||
* principal node type
|
||||
*/
|
||||
txNameTest(nsIAtom* aPrefix, nsIAtom* aLocalName, PRInt32 aNSID,
|
||||
Node::NodeType aNodeType);
|
||||
PRUint16 aNodeType);
|
||||
|
||||
~txNameTest();
|
||||
|
||||
|
@ -243,7 +244,7 @@ private:
|
|||
nsCOMPtr<nsIAtom> mPrefix;
|
||||
nsCOMPtr<nsIAtom> mLocalName;
|
||||
PRInt32 mNamespace;
|
||||
Node::NodeType mNodeType;
|
||||
PRUint16 mNodeType;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -362,10 +363,10 @@ public:
|
|||
TX_DECL_EXPR;
|
||||
|
||||
private:
|
||||
void fromDescendants(Node* node, txIMatchContext* aContext,
|
||||
txNodeSet* nodes);
|
||||
void fromDescendantsRev(Node* node, txIMatchContext* aContext,
|
||||
txNodeSet* nodes);
|
||||
void fromDescendants(const txXPathNode& aNode, txIMatchContext* aCs,
|
||||
txNodeSet* aNodes);
|
||||
void fromDescendantsRev(const txXPathNode& aNode, txIMatchContext* aCs,
|
||||
txNodeSet* aNodes);
|
||||
|
||||
nsAutoPtr<txNodeTest> mNodeTest;
|
||||
LocationStepType mAxisIdentifier;
|
||||
|
@ -619,7 +620,7 @@ private:
|
|||
* Selects from the descendants of the context node
|
||||
* all nodes that match the Expr
|
||||
*/
|
||||
nsresult evalDescendants(Expr* aStep, Node* aNode,
|
||||
nsresult evalDescendants(Expr* aStep, const txXPathNode& aNode,
|
||||
txIMatchContext* aContext,
|
||||
txNodeSet* resNodes);
|
||||
};
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
#include "txAtoms.h"
|
||||
#include "txIXPathContext.h"
|
||||
#include "txStringUtils.h"
|
||||
|
||||
#include "txXPathNode.h"
|
||||
|
||||
/**
|
||||
* Creates an Attribute Value Template using the given value
|
||||
|
@ -692,11 +692,11 @@ txExprParser::createLocationStep(txExprLexer& lexer, txIParseContext* aContext,
|
|||
switch (axisIdentifier) {
|
||||
case LocationStep::ATTRIBUTE_AXIS:
|
||||
nodeTest = new txNameTest(prefix, lName, nspace,
|
||||
Node::ATTRIBUTE_NODE);
|
||||
txXPathNodeType::ATTRIBUTE_NODE);
|
||||
break;
|
||||
default:
|
||||
nodeTest = new txNameTest(prefix, lName, nspace,
|
||||
Node::ELEMENT_NODE);
|
||||
txXPathNodeType::ELEMENT_NODE);
|
||||
break;
|
||||
}
|
||||
NS_ENSURE_TRUE(nodeTest, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
#include "txForwardContext.h"
|
||||
#include "txNodeSet.h"
|
||||
|
||||
Node* txForwardContext::getContextNode()
|
||||
const txXPathNode& txForwardContext::getContextNode()
|
||||
{
|
||||
return mContextNode;
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ nsresult txForwardContext::getVariable(PRInt32 aNamespace, nsIAtom* aLName,
|
|||
return mInner->getVariable(aNamespace, aLName, aResult);
|
||||
}
|
||||
|
||||
MBool txForwardContext::isStripSpaceAllowed(Node* aNode)
|
||||
MBool txForwardContext::isStripSpaceAllowed(const txXPathNode& aNode)
|
||||
{
|
||||
NS_ASSERTION(mInner, "mInner is null!!!");
|
||||
return mInner->isStripSpaceAllowed(aNode);
|
||||
|
|
|
@ -41,12 +41,14 @@
|
|||
|
||||
#include "txIXPathContext.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "txNodeSet.h"
|
||||
|
||||
class txNodeSet;
|
||||
|
||||
class txForwardContext : public txIEvalContext
|
||||
{
|
||||
public:
|
||||
txForwardContext(txIMatchContext* aContext, Node* aContextNode,
|
||||
txForwardContext(txIMatchContext* aContext,
|
||||
const txXPathNode& aContextNode,
|
||||
txNodeSet* aContextNodeSet)
|
||||
: mInner(aContext),
|
||||
mContextNode(aContextNode),
|
||||
|
@ -59,7 +61,7 @@ public:
|
|||
|
||||
private:
|
||||
txIMatchContext* mInner;
|
||||
Node* mContextNode;
|
||||
const txXPathNode& mContextNode;
|
||||
nsRefPtr<txNodeSet> mContextSet;
|
||||
};
|
||||
|
||||
|
|
|
@ -43,10 +43,12 @@
|
|||
#include "nsIAtom.h"
|
||||
#include "txError.h"
|
||||
|
||||
class txAExprResult;
|
||||
class FunctionCall;
|
||||
class Node;
|
||||
class nsAString;
|
||||
class nsIAtom;
|
||||
class txAExprResult;
|
||||
class txResultRecycler;
|
||||
class txXPathNode;
|
||||
|
||||
/*
|
||||
* txIParseContext
|
||||
|
@ -114,7 +116,7 @@ public:
|
|||
* Is whitespace stripping allowed for the given node?
|
||||
* See http://www.w3.org/TR/xslt#strip
|
||||
*/
|
||||
virtual MBool isStripSpaceAllowed(Node* aNode) = 0;
|
||||
virtual MBool isStripSpaceAllowed(const txXPathNode& aNode) = 0;
|
||||
|
||||
/**
|
||||
* Returns a pointer to the private context
|
||||
|
@ -132,7 +134,7 @@ public:
|
|||
#define TX_DECL_MATCH_CONTEXT \
|
||||
nsresult getVariable(PRInt32 aNamespace, nsIAtom* aLName, \
|
||||
txAExprResult*& aResult); \
|
||||
MBool isStripSpaceAllowed(Node* aNode); \
|
||||
MBool isStripSpaceAllowed(const txXPathNode& aNode); \
|
||||
void* getPrivateContext(); \
|
||||
txResultRecycler* recycler(); \
|
||||
void receiveError(const nsAString& aMsg, nsresult aRes)
|
||||
|
@ -147,7 +149,7 @@ public:
|
|||
/*
|
||||
* Get the context node.
|
||||
*/
|
||||
virtual Node* getContextNode() = 0;
|
||||
virtual const txXPathNode& getContextNode() = 0;
|
||||
|
||||
/*
|
||||
* Get the size of the context node set.
|
||||
|
@ -163,7 +165,7 @@ public:
|
|||
|
||||
#define TX_DECL_EVAL_CONTEXT \
|
||||
TX_DECL_MATCH_CONTEXT; \
|
||||
Node* getContextNode(); \
|
||||
const txXPathNode& getContextNode(); \
|
||||
PRUint32 size(); \
|
||||
PRUint32 position()
|
||||
|
||||
|
|
|
@ -53,75 +53,92 @@ LocationStep::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
nsresult rv = aContext->recycler()->getNodeSet(getter_AddRefs(nodes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
MBool reverse = MB_FALSE;
|
||||
txXPathTreeWalker walker(aContext->getContextNode());
|
||||
|
||||
Node* node = aContext->getContextNode();
|
||||
switch (mAxisIdentifier) {
|
||||
case ANCESTOR_AXIS :
|
||||
node = node->getXPathParent();
|
||||
//-- do not break here
|
||||
case ANCESTOR_OR_SELF_AXIS :
|
||||
reverse = MB_TRUE;
|
||||
while (node) {
|
||||
if (mNodeTest->matches(node, aContext)) {
|
||||
nodes->append(node);
|
||||
}
|
||||
node = node->getXPathParent();
|
||||
}
|
||||
break;
|
||||
case ATTRIBUTE_AXIS :
|
||||
case ANCESTOR_AXIS:
|
||||
{
|
||||
NamedNodeMap* atts = node->getAttributes();
|
||||
if (atts) {
|
||||
for (PRUint32 i = 0; i < atts->getLength(); i++) {
|
||||
Node* attr = atts->item(i);
|
||||
if (attr->getNamespaceID() != kNameSpaceID_XMLNS &&
|
||||
mNodeTest->matches(attr, aContext))
|
||||
nodes->append(attr);
|
||||
if (!walker.moveToParent()) {
|
||||
break;
|
||||
}
|
||||
// do not break here
|
||||
}
|
||||
case ANCESTOR_OR_SELF_AXIS:
|
||||
{
|
||||
nodes->setReverse();
|
||||
|
||||
do {
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
} while (walker.moveToParent());
|
||||
|
||||
break;
|
||||
}
|
||||
case ATTRIBUTE_AXIS:
|
||||
{
|
||||
if (!walker.moveToFirstAttribute()) {
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
} while (walker.moveToNextAttribute());
|
||||
break;
|
||||
}
|
||||
case DESCENDANT_OR_SELF_AXIS:
|
||||
{
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
// do not break here
|
||||
}
|
||||
case DESCENDANT_AXIS:
|
||||
{
|
||||
fromDescendants(walker.getCurrentPosition(), aContext, nodes);
|
||||
break;
|
||||
}
|
||||
case FOLLOWING_AXIS:
|
||||
{
|
||||
if (walker.getNodeType() == txXPathNodeType::ATTRIBUTE_NODE) {
|
||||
walker.moveToParent();
|
||||
fromDescendants(walker.getCurrentPosition(), aContext, nodes);
|
||||
}
|
||||
PRBool cont = PR_TRUE;
|
||||
while (!walker.moveToNextSibling()) {
|
||||
if (!walker.moveToParent()) {
|
||||
cont = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (cont) {
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
|
||||
fromDescendants(walker.getCurrentPosition(), aContext, nodes);
|
||||
|
||||
while (!walker.moveToNextSibling()) {
|
||||
if (!walker.moveToParent()) {
|
||||
cont = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DESCENDANT_OR_SELF_AXIS :
|
||||
if (mNodeTest->matches(node, aContext))
|
||||
nodes->append(node);
|
||||
//-- do not break here
|
||||
case DESCENDANT_AXIS :
|
||||
fromDescendants(node, aContext, nodes);
|
||||
break;
|
||||
case FOLLOWING_AXIS :
|
||||
case FOLLOWING_SIBLING_AXIS:
|
||||
{
|
||||
if ( node->getNodeType() == Node::ATTRIBUTE_NODE) {
|
||||
node = node->getXPathParent();
|
||||
fromDescendants(node, aContext, nodes);
|
||||
}
|
||||
while (node && !node->getNextSibling()) {
|
||||
node = node->getXPathParent();
|
||||
}
|
||||
while (node) {
|
||||
node = node->getNextSibling();
|
||||
|
||||
if (mNodeTest->matches(node, aContext))
|
||||
nodes->append(node);
|
||||
|
||||
if (node->hasChildNodes())
|
||||
fromDescendants(node, aContext, nodes);
|
||||
|
||||
while (node && !node->getNextSibling()) {
|
||||
node = node->getParentNode();
|
||||
while (walker.moveToNextSibling()) {
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FOLLOWING_SIBLING_AXIS :
|
||||
node = node->getNextSibling();
|
||||
while (node) {
|
||||
if (mNodeTest->matches(node, aContext))
|
||||
nodes->append(node);
|
||||
node = node->getNextSibling();
|
||||
}
|
||||
break;
|
||||
case NAMESPACE_AXIS : //-- not yet implemented
|
||||
case NAMESPACE_AXIS: //-- not yet implemented
|
||||
#if 0
|
||||
// XXX DEBUG OUTPUT
|
||||
cout << "namespace axis not yet implemented"<<endl;
|
||||
|
@ -129,106 +146,121 @@ LocationStep::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
break;
|
||||
case PARENT_AXIS :
|
||||
{
|
||||
Node* parent = node->getXPathParent();
|
||||
if (mNodeTest->matches(parent, aContext))
|
||||
nodes->append(parent);
|
||||
if (walker.moveToParent() &&
|
||||
mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PRECEDING_AXIS :
|
||||
reverse = MB_TRUE;
|
||||
while (node && !node->getPreviousSibling()) {
|
||||
node = node->getXPathParent();
|
||||
case PRECEDING_AXIS:
|
||||
{
|
||||
nodes->setReverse();
|
||||
|
||||
PRBool cont = PR_TRUE;
|
||||
while (!walker.moveToPreviousSibling()) {
|
||||
if (!walker.moveToParent()) {
|
||||
cont = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (node) {
|
||||
node = node->getPreviousSibling();
|
||||
while (cont) {
|
||||
fromDescendantsRev(walker.getCurrentPosition(), aContext, nodes);
|
||||
|
||||
if (node->hasChildNodes())
|
||||
fromDescendantsRev(node, aContext, nodes);
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
|
||||
if (mNodeTest->matches(node, aContext))
|
||||
nodes->append(node);
|
||||
|
||||
while (node && !node->getPreviousSibling()) {
|
||||
node = node->getParentNode();
|
||||
while (!walker.moveToPreviousSibling()) {
|
||||
if (!walker.moveToParent()) {
|
||||
cont = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PRECEDING_SIBLING_AXIS:
|
||||
reverse = MB_TRUE;
|
||||
node = node->getPreviousSibling();
|
||||
while (node) {
|
||||
if (mNodeTest->matches(node, aContext))
|
||||
nodes->append(node);
|
||||
node = node->getPreviousSibling();
|
||||
}
|
||||
break;
|
||||
case SELF_AXIS :
|
||||
if (mNodeTest->matches(node, aContext))
|
||||
nodes->append(node);
|
||||
break;
|
||||
default: //-- Children Axis
|
||||
{
|
||||
node = node->getFirstChild();
|
||||
while (node) {
|
||||
if (mNodeTest->matches(node, aContext))
|
||||
nodes->append(node);
|
||||
node = node->getNextSibling();
|
||||
nodes->setReverse();
|
||||
|
||||
while (walker.moveToPreviousSibling()) {
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} //-- switch
|
||||
case SELF_AXIS:
|
||||
{
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: // Children Axis
|
||||
{
|
||||
if (!walker.moveToFirstChild()) {
|
||||
break;
|
||||
}
|
||||
|
||||
//-- apply predicates
|
||||
do {
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
} while (walker.moveToNextSibling());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply predicates
|
||||
if (!isEmpty()) {
|
||||
rv = evaluatePredicates(nodes, aContext);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (reverse)
|
||||
nodes->reverse();
|
||||
nodes->unsetReverse();
|
||||
|
||||
NS_ADDREF(*aResult = nodes);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void LocationStep::fromDescendants(Node* node,
|
||||
txIMatchContext* cs,
|
||||
txNodeSet* nodes)
|
||||
void LocationStep::fromDescendants(const txXPathNode& aNode,
|
||||
txIMatchContext* aCs,
|
||||
txNodeSet* aNodes)
|
||||
{
|
||||
if (!node)
|
||||
txXPathTreeWalker walker(aNode);
|
||||
if (!walker.moveToFirstChild()) {
|
||||
return;
|
||||
|
||||
Node* child = node->getFirstChild();
|
||||
while (child) {
|
||||
if (mNodeTest->matches(child, cs))
|
||||
nodes->append(child);
|
||||
//-- check childs descendants
|
||||
if (child->hasChildNodes())
|
||||
fromDescendants(child, cs, nodes);
|
||||
|
||||
child = child->getNextSibling();
|
||||
}
|
||||
|
||||
do {
|
||||
const txXPathNode& child = walker.getCurrentPosition();
|
||||
if (mNodeTest->matches(child, aCs)) {
|
||||
aNodes->append(child);
|
||||
}
|
||||
fromDescendants(child, aCs, aNodes);
|
||||
} while (walker.moveToNextSibling());
|
||||
}
|
||||
|
||||
void LocationStep::fromDescendantsRev(Node* node,
|
||||
txIMatchContext* cs,
|
||||
txNodeSet* nodes)
|
||||
void LocationStep::fromDescendantsRev(const txXPathNode& aNode,
|
||||
txIMatchContext* aCs,
|
||||
txNodeSet* aNodes)
|
||||
{
|
||||
if (!node)
|
||||
txXPathTreeWalker walker(aNode);
|
||||
if (!walker.moveToLastChild()) {
|
||||
return;
|
||||
|
||||
Node* child = node->getLastChild();
|
||||
while (child) {
|
||||
//-- check childs descendants
|
||||
if (child->hasChildNodes())
|
||||
fromDescendantsRev(child, cs, nodes);
|
||||
|
||||
if (mNodeTest->matches(child, cs))
|
||||
nodes->append(child);
|
||||
|
||||
child = child->getPreviousSibling();
|
||||
}
|
||||
|
||||
do {
|
||||
const txXPathNode& child = walker.getCurrentPosition();
|
||||
fromDescendantsRev(child, aCs, aNodes);
|
||||
|
||||
if (mNodeTest->matches(child, aCs)) {
|
||||
aNodes->append(child);
|
||||
}
|
||||
|
||||
} while (walker.moveToPreviousSibling());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,10 +25,11 @@
|
|||
|
||||
#include "Expr.h"
|
||||
#include "txAtoms.h"
|
||||
#include "txXPathTreeWalker.h"
|
||||
#include "txIXPathContext.h"
|
||||
|
||||
txNameTest::txNameTest(nsIAtom* aPrefix, nsIAtom* aLocalName, PRInt32 aNSID,
|
||||
Node::NodeType aNodeType)
|
||||
PRUint16 aNodeType)
|
||||
:mPrefix(aPrefix), mLocalName(aLocalName), mNamespace(aNSID),
|
||||
mNodeType(aNodeType)
|
||||
{
|
||||
|
@ -41,12 +42,9 @@ txNameTest::~txNameTest()
|
|||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Determines whether this txNodeTest matches the given node
|
||||
*/
|
||||
MBool txNameTest::matches(Node* aNode, txIMatchContext* aContext)
|
||||
PRBool txNameTest::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
||||
{
|
||||
if (!aNode || aNode->getNodeType() != mNodeType)
|
||||
if (txXPathNodeUtils::getNodeType(aNode) != mNodeType)
|
||||
return MB_FALSE;
|
||||
|
||||
// Totally wild?
|
||||
|
@ -54,7 +52,7 @@ MBool txNameTest::matches(Node* aNode, txIMatchContext* aContext)
|
|||
return MB_TRUE;
|
||||
|
||||
// Compare namespaces
|
||||
if (aNode->getNamespaceID() != mNamespace)
|
||||
if (txXPathNodeUtils::getNamespaceID(aNode) != mNamespace)
|
||||
return MB_FALSE;
|
||||
|
||||
// Name wild?
|
||||
|
@ -62,8 +60,7 @@ MBool txNameTest::matches(Node* aNode, txIMatchContext* aContext)
|
|||
return MB_TRUE;
|
||||
|
||||
// Compare local-names
|
||||
nsCOMPtr<nsIAtom> localName;
|
||||
aNode->getLocalName(getter_AddRefs(localName));
|
||||
nsCOMPtr<nsIAtom> localName = txXPathNodeUtils::getLocalName(aNode);
|
||||
return localName == mLocalName;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,95 +31,133 @@
|
|||
*/
|
||||
|
||||
#include "txNodeSet.h"
|
||||
#include "dom.h"
|
||||
#include "XMLDOMUtils.h"
|
||||
#include <string.h>
|
||||
#include "TxLog.h"
|
||||
#include "nsMemory.h"
|
||||
|
||||
static const int kTxNodeSetMinSize = 4;
|
||||
static const int kTxNodeSetGrowFactor = 2;
|
||||
|
||||
/*
|
||||
* Implementation of an XPath NodeSet
|
||||
/**
|
||||
* Implementation of an XPath nodeset
|
||||
*/
|
||||
|
||||
/*
|
||||
* Creates a new empty NodeSet
|
||||
*/
|
||||
static const PRInt32 kTxNodeSetMinSize = 4;
|
||||
static const PRInt32 kTxNodeSetGrowFactor = 2;
|
||||
|
||||
#define kForward 1
|
||||
#define kReversed -1
|
||||
|
||||
txNodeSet::txNodeSet(txResultRecycler* aRecycler)
|
||||
: txAExprResult(aRecycler),
|
||||
mElements(0),
|
||||
mBufferSize(0),
|
||||
mElementCount(0)
|
||||
mStart(nsnull),
|
||||
mEnd(nsnull),
|
||||
mStartBuffer(nsnull),
|
||||
mEndBuffer(nsnull),
|
||||
mDirection(kForward),
|
||||
mMarks(nsnull)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a new NodeSet containing the supplied Node
|
||||
*/
|
||||
txNodeSet::txNodeSet(Node* aNode, txResultRecycler* aRecycler)
|
||||
txNodeSet::txNodeSet(const txXPathNode& aNode, txResultRecycler* aRecycler)
|
||||
: txAExprResult(aRecycler),
|
||||
mElements(new Node*[1]),
|
||||
mBufferSize(1),
|
||||
mElementCount(1)
|
||||
mStart(nsnull),
|
||||
mEnd(nsnull),
|
||||
mStartBuffer(nsnull),
|
||||
mEndBuffer(nsnull),
|
||||
mDirection(kForward),
|
||||
mMarks(nsnull)
|
||||
{
|
||||
NS_ASSERTION(aNode, "missing node to txNodeSet::txNodeSet");
|
||||
if (!mElements) {
|
||||
NS_ASSERTION(0, "out of memory");
|
||||
mBufferSize = 0;
|
||||
mElementCount = 0;
|
||||
}
|
||||
else {
|
||||
mElements[0] = aNode;
|
||||
if (!ensureGrowSize(1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
new(mStart) txXPathNode(aNode);
|
||||
++mEnd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a new NodeSet, copying the Node references from the source
|
||||
* NodeSet
|
||||
*/
|
||||
txNodeSet::txNodeSet(const txNodeSet& aSource, txResultRecycler* aRecycler)
|
||||
: txAExprResult(aRecycler),
|
||||
mElements(0),
|
||||
mBufferSize(0),
|
||||
mElementCount(0)
|
||||
mStart(nsnull),
|
||||
mEnd(nsnull),
|
||||
mStartBuffer(nsnull),
|
||||
mEndBuffer(nsnull),
|
||||
mDirection(kForward),
|
||||
mMarks(nsnull)
|
||||
{
|
||||
append(&aSource);
|
||||
append(aSource);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds the specified Node to this NodeSet if it is not already in this
|
||||
* NodeSet. The node is inserted according to document order.
|
||||
* @param aNode the Node to add to the NodeSet
|
||||
* @return errorcode.
|
||||
*/
|
||||
nsresult txNodeSet::add(Node* aNode)
|
||||
txNodeSet::~txNodeSet()
|
||||
{
|
||||
NS_ASSERTION(aNode, "missing node to txNodeSet::add");
|
||||
if (!aNode)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
delete [] mMarks;
|
||||
|
||||
MBool nonDup;
|
||||
int pos = findPosition(aNode, 0, mElementCount - 1, nonDup);
|
||||
if (nonDup) {
|
||||
if (!ensureSize(mElementCount + 1))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
memmove(mElements + pos + 1,
|
||||
mElements + pos,
|
||||
(mElementCount - pos) * sizeof(Node*));
|
||||
mElements[pos] = aNode;
|
||||
++mElementCount;
|
||||
if (mStartBuffer) {
|
||||
while (mStart < mEnd) {
|
||||
mStart->~txXPathNode();
|
||||
++mStart;
|
||||
}
|
||||
|
||||
nsMemory::Free(mStartBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult txNodeSet::add(const txXPathNode& aNode)
|
||||
{
|
||||
NS_ASSERTION(mDirection == kForward,
|
||||
"only append(aNode) is supported on reversed nodesets");
|
||||
|
||||
if (isEmpty()) {
|
||||
return append(aNode);
|
||||
}
|
||||
|
||||
PRBool dupe;
|
||||
txXPathNode* pos = findPosition(aNode, mStart, mEnd, dupe);
|
||||
|
||||
if (dupe) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// save pos, ensureGrowSize messes with the pointers
|
||||
PRInt32 moveSize = mEnd - pos;
|
||||
PRInt32 offset = pos - mStart;
|
||||
if (!ensureGrowSize(1)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
// set pos to where it was
|
||||
pos = mStart + offset;
|
||||
|
||||
if (moveSize > 0) {
|
||||
memmove(pos + 1, pos, moveSize * sizeof(txXPathNode));
|
||||
}
|
||||
|
||||
new(pos) txXPathNode(aNode);
|
||||
++mEnd;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds the nodes in specified NodeSet to this NodeSet. The resulting NodeSet
|
||||
* is sorted in document order and does not contain any duplicate nodes.
|
||||
* @param aNodes the NodeSet to add, must be in document order.
|
||||
* @return true on success. false on failure.
|
||||
*/
|
||||
nsresult txNodeSet::add(const txNodeSet& aNodes)
|
||||
{
|
||||
return add(aNodes, copyElements);
|
||||
}
|
||||
|
||||
/*
|
||||
nsresult txNodeSet::addAndTransfer(txNodeSet* aNodes)
|
||||
{
|
||||
// failure is out-of-memory, transfer didn't happen
|
||||
nsresult rv = add(*aNodes, transferElements);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
#ifdef TX_DONT_RECYCLE_BUFFER
|
||||
if (aNodes->mStartBuffer) {
|
||||
nsMemory::Free(aNodes->mStartBuffer);
|
||||
aNodes->mStartBuffer = aNodes->mEndBuffer = nsnull;
|
||||
}
|
||||
#endif
|
||||
aNodes->mStart = aNodes->mEnd = aNodes->mStartBuffer;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* add(aNodeSet, aTransferOp)
|
||||
*
|
||||
* The code is optimized to make a minimum number of calls to
|
||||
* Node::compareDocumentPosition. The idea is this:
|
||||
* We have the two nodesets (number indicate "document position")
|
||||
|
@ -129,267 +167,320 @@ nsresult txNodeSet::add(Node* aNode)
|
|||
* _ _ _ _ _ _ _ _ <- result
|
||||
*
|
||||
*
|
||||
* We select the last node in the smallest nodeset and find where in the other
|
||||
* nodeset it would be inserted. In this case we would take the 7 from the
|
||||
* first nodeset and find the position between the 6 and 8 in the second.
|
||||
* We then take the nodes after the insert-position and move it to the end of
|
||||
* the resulting nodeset, and then do the same for the node from the smaller
|
||||
* nodeset. Which in this case means that we'd first move the 8 and 9 nodes,
|
||||
* and then the 7 node, giving us the following:
|
||||
* When merging these nodesets into the result, the nodes are transfered
|
||||
* in chunks to the end of the buffer so that each chunk does not contain
|
||||
* a node from the other nodeset, in document order.
|
||||
*
|
||||
* We select the last non-transfered node in the first nodeset and find
|
||||
* where in the other nodeset it would be inserted. In this case we would
|
||||
* take the 7 from the first nodeset and find the position between the
|
||||
* 6 and 8 in the second. We then take the nodes after the insert-position
|
||||
* and transfer them to the end of the resulting nodeset. Which in this case
|
||||
* means that we first transfered the 8 and 9 nodes, giving us the following:
|
||||
*
|
||||
* 1 3 <- source 1
|
||||
* 1 3 7 <- source 1
|
||||
* 2 3 6 <- source 2
|
||||
* _ _ _ _ _ 7 8 9 <- result
|
||||
* _ _ _ _ _ _ 8 9 <- result
|
||||
*
|
||||
* The corresponding procedure is done for the second nodeset, that is
|
||||
* the insertion position of the 6 in the first nodeset is found, which
|
||||
* is between the 3 and the 7. The 7 is memmoved (as it stays within
|
||||
* the same nodeset) to the result buffer.
|
||||
*
|
||||
* As the result buffer is filled from the end, it is safe to share the
|
||||
* buffer between this nodeset and the result.
|
||||
*
|
||||
* Repeat until one of the nodesets are empty. If we find a duplicate node
|
||||
* when searching for where insertposition we skip the step where we move the
|
||||
* node from the smaller nodeset to the resulting nodeset. So in this next
|
||||
* step in the example we would only move the 3 and 6 nodes from the second
|
||||
* nodeset and then just remove the 3 node from the first nodeset. Giving:
|
||||
*
|
||||
* 1 <- source 1
|
||||
* 2 <- source 2
|
||||
* _ _ _ 3 6 7 8 9 <- result
|
||||
*
|
||||
* We might therefor end up with some blanks in the bigining of the resulting
|
||||
* nodeset, which we simply fix by moving all the nodes one step down.
|
||||
* This is repeated until both of the nodesets are empty.
|
||||
*
|
||||
* If we find a duplicate node when searching for where insertposition we
|
||||
* check for sequences of duplicate nodes, which can be optimized.
|
||||
*
|
||||
*/
|
||||
nsresult txNodeSet::add(const txNodeSet* aNodes)
|
||||
nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer)
|
||||
{
|
||||
NS_ASSERTION(aNodes, "missing nodeset to txNodeSet::add");
|
||||
if (!aNodes)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
NS_ASSERTION(mDirection == kForward,
|
||||
"only append(aNode) is supported on reversed nodesets");
|
||||
|
||||
if (aNodes->mElementCount == 0)
|
||||
if (aNodes.isEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// This is probably a rather common case, so lets try to shortcut
|
||||
if (mElementCount == 0 ||
|
||||
mElements[mElementCount-1]->compareDocumentPosition(aNodes->mElements[0]) < 0)
|
||||
return append(aNodes);
|
||||
|
||||
if (!ensureSize(mElementCount + aNodes->mElementCount))
|
||||
if (!ensureGrowSize(aNodes.size())) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Index of last node in this nodeset
|
||||
int thisPos = mElementCount - 1;
|
||||
// Index of last node in other nodeset
|
||||
int otherPos = aNodes->mElementCount - 1;
|
||||
// Index in result where last insert was done.
|
||||
int lastInsertPos = mElementCount + aNodes->mElementCount;
|
||||
|
||||
while (thisPos >= 0 && otherPos >= 0) {
|
||||
if (thisPos > otherPos) {
|
||||
int pos;
|
||||
MBool nonDup;
|
||||
// Find where in the remaining nodes in this nodeset a node from
|
||||
// the other nodeset should be inserted
|
||||
pos = findPosition(aNodes->mElements[otherPos], 0, thisPos,
|
||||
nonDup);
|
||||
// This is probably a rather common case, so lets try to shortcut.
|
||||
if (mStart == mEnd ||
|
||||
txXPathNodeUtils::comparePosition(mEnd[-1], *aNodes.mStart) < 0) {
|
||||
aTransfer(mEnd, aNodes.mStart, aNodes.mEnd);
|
||||
mEnd += aNodes.size();
|
||||
|
||||
// Move nodes in this nodeset
|
||||
lastInsertPos -= thisPos - pos + 1;
|
||||
memmove(mElements + lastInsertPos,
|
||||
mElements + pos,
|
||||
(thisPos - pos + 1) * sizeof(Node*));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Copy node from the other nodeset unless it's a dup
|
||||
if (nonDup)
|
||||
mElements[--lastInsertPos] = aNodes->mElements[otherPos];
|
||||
|
||||
// Adjust positions in both nodesets
|
||||
thisPos = pos - 1;
|
||||
--otherPos;
|
||||
// Last element in this nodeset
|
||||
txXPathNode* thisPos = mEnd;
|
||||
|
||||
// Last element of the other nodeset
|
||||
txXPathNode* otherPos = aNodes.mEnd;
|
||||
|
||||
// Pointer to the insertion point in this nodeset
|
||||
txXPathNode* insertPos = mEndBuffer;
|
||||
|
||||
PRBool dupe;
|
||||
txXPathNode* pos;
|
||||
PRInt32 count;
|
||||
while (thisPos > mStart || otherPos > aNodes.mStart) {
|
||||
// Find where the last remaining node of this nodeset would
|
||||
// be inserted in the other nodeset.
|
||||
if (thisPos > mStart) {
|
||||
pos = findPosition(thisPos[-1], aNodes.mStart, otherPos, dupe);
|
||||
|
||||
if (dupe) {
|
||||
--thisPos; // this is already added
|
||||
// check dupe sequence
|
||||
while (thisPos > mStart && pos > aNodes.mStart &&
|
||||
thisPos[-1] == pos[-1]) {
|
||||
--thisPos;
|
||||
--pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
int pos;
|
||||
MBool nonDup;
|
||||
// Find where in the remaining nodes in the other nodeset a node
|
||||
// from this nodeset should be inserted
|
||||
pos = aNodes->findPosition(mElements[thisPos], 0, otherPos,
|
||||
nonDup);
|
||||
pos = aNodes.mStart;
|
||||
}
|
||||
|
||||
// Copy nodes from other nodeset to this
|
||||
lastInsertPos -= otherPos - pos + 1;
|
||||
memcpy(mElements + lastInsertPos,
|
||||
aNodes->mElements + pos,
|
||||
(otherPos - pos + 1) * sizeof(Node*));
|
||||
// Transfer the otherNodes after the insertion point to the result
|
||||
count = otherPos - pos;
|
||||
if (count > 0) {
|
||||
insertPos -= count;
|
||||
aTransfer(insertPos, pos, otherPos);
|
||||
otherPos -= count;
|
||||
}
|
||||
|
||||
// Move node in this nodeset unless it's a dup
|
||||
if (nonDup)
|
||||
mElements[--lastInsertPos] = mElements[thisPos];
|
||||
|
||||
// Adjust positions in both nodesets
|
||||
otherPos = pos - 1;
|
||||
--thisPos;
|
||||
// Find where the last remaining node of the otherNodeset would
|
||||
// be inserted in this nodeset.
|
||||
if (otherPos > aNodes.mStart) {
|
||||
pos = findPosition(otherPos[-1], mStart, thisPos, dupe);
|
||||
|
||||
if (dupe) {
|
||||
--otherPos; // this is already added
|
||||
// check dupe sequence
|
||||
while (otherPos > aNodes.mStart && pos > mStart &&
|
||||
otherPos[-1] == pos[-1]) {
|
||||
--otherPos;
|
||||
--pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
pos = mStart;
|
||||
}
|
||||
|
||||
// Move the nodes from this nodeset after the insertion point
|
||||
// to the result
|
||||
count = thisPos - pos;
|
||||
if (count > 0) {
|
||||
insertPos -= count;
|
||||
memmove(insertPos, pos, count * sizeof(txXPathNode));
|
||||
thisPos -= count;
|
||||
}
|
||||
}
|
||||
mStart = insertPos;
|
||||
mEnd = mEndBuffer;
|
||||
|
||||
if (thisPos >= 0) {
|
||||
// There were some elements still left in this nodeset that need to
|
||||
// be moved
|
||||
lastInsertPos -= thisPos + 1;
|
||||
memmove(mElements + lastInsertPos,
|
||||
mElements,
|
||||
(thisPos + 1) * sizeof(Node*));
|
||||
}
|
||||
else if (otherPos >= 0) {
|
||||
// There were some elements still left in the other nodeset that need
|
||||
// to be copied
|
||||
lastInsertPos -= otherPos + 1;
|
||||
memcpy(mElements + lastInsertPos,
|
||||
aNodes->mElements,
|
||||
(otherPos + 1) * sizeof(Node*));
|
||||
}
|
||||
|
||||
// if lastInsertPos != 0 then we have found some duplicates causing the
|
||||
// first element to not be placed at mElements[0]
|
||||
mElementCount += aNodes->mElementCount - lastInsertPos;
|
||||
if (lastInsertPos) {
|
||||
memmove(mElements,
|
||||
mElements + lastInsertPos,
|
||||
mElementCount * sizeof(Node*));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Append API
|
||||
* These functions should be used with care.
|
||||
* They are intended to be used when the caller assures that the resulting
|
||||
* NodeSet remains in document order.
|
||||
* nodeset remains in document order.
|
||||
* Abuse will break document order, and cause errors in the result.
|
||||
* These functions are significantly faster than the add API, as no
|
||||
* Node::OrderInfo structs will be generated.
|
||||
* order info operations will be performed.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Appends the specified Node to the end of this NodeSet
|
||||
* @param aNode the Node to append to the NodeSet
|
||||
* @return true on success. false on failure.
|
||||
*/
|
||||
nsresult txNodeSet::append(Node* aNode)
|
||||
nsresult
|
||||
txNodeSet::append(const txXPathNode& aNode)
|
||||
{
|
||||
NS_ASSERTION(aNode, "missing node to txNodeSet::append");
|
||||
if (!aNode)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (!ensureSize(mElementCount + 1))
|
||||
if (!ensureGrowSize(1)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
mElements[mElementCount++] = aNode;
|
||||
if (mDirection == kForward) {
|
||||
new(mEnd) txXPathNode(aNode);
|
||||
++mEnd;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
new(--mStart) txXPathNode(aNode);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Appends the nodes in the specified NodeSet to the end of this NodeSet
|
||||
* @param aNodes the NodeSet to append to the NodeSet
|
||||
* @return true on success. false on failure.
|
||||
*/
|
||||
nsresult txNodeSet::append(const txNodeSet* aNodes)
|
||||
nsresult
|
||||
txNodeSet::append(const txNodeSet& aNodes)
|
||||
{
|
||||
NS_ASSERTION(aNodes, "missing nodeset to txNodeSet::append");
|
||||
if (!aNodes)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
NS_ASSERTION(mDirection == kForward,
|
||||
"only append(aNode) is supported on reversed nodesets");
|
||||
|
||||
if (!ensureSize(mElementCount + aNodes->mElementCount))
|
||||
if (aNodes.isEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRInt32 appended = aNodes.size();
|
||||
if (!ensureGrowSize(appended)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
memcpy(mElements + mElementCount,
|
||||
aNodes->mElements,
|
||||
aNodes->mElementCount * sizeof(Node*));
|
||||
mElementCount += aNodes->mElementCount;
|
||||
copyElements(mEnd, aNodes.mStart, aNodes.mEnd);
|
||||
mEnd += appended;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reverse the order of the nodes.
|
||||
*/
|
||||
void txNodeSet::reverse()
|
||||
nsresult
|
||||
txNodeSet::mark(PRInt32 aIndex)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < mElementCount / 2; ++i) {
|
||||
Node* tmp;
|
||||
tmp = mElements[i];
|
||||
mElements[i] = mElements[mElementCount - 1 - i];
|
||||
mElements[mElementCount - 1 - i] = tmp;
|
||||
NS_ASSERTION(aIndex >= 0 && mStart && mEnd - mStart > aIndex,
|
||||
"index out of bounds");
|
||||
if (!mMarks) {
|
||||
PRInt32 length = size();
|
||||
mMarks = new PRPackedBool[length];
|
||||
NS_ENSURE_TRUE(mMarks, NS_ERROR_OUT_OF_MEMORY);
|
||||
memset(mMarks, 0, length * sizeof(PRPackedBool));
|
||||
}
|
||||
if (mDirection == kForward) {
|
||||
mMarks[aIndex] = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
mMarks[size() - aIndex - 1] = PR_TRUE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the index of the specified Node,
|
||||
* or -1 if the Node is not contained in the NodeSet
|
||||
* @param aNode the Node to get the index for
|
||||
* @return index of specified node or -1 if the node does not exist
|
||||
*/
|
||||
int txNodeSet::indexOf(Node* aNode) const
|
||||
nsresult
|
||||
txNodeSet::sweep()
|
||||
{
|
||||
// XXX this doesn't fully work since attribute-nodes are broken
|
||||
// and can't be pointer-compared. However it's the best we can
|
||||
// do for now.
|
||||
int i;
|
||||
for (i = 0; i < mElementCount; ++i) {
|
||||
if (mElements[i] == aNode)
|
||||
return i;
|
||||
if (!mMarks) {
|
||||
// sweep everything
|
||||
clear();
|
||||
}
|
||||
|
||||
PRInt32 chunk, pos = 0;
|
||||
PRInt32 length = size();
|
||||
txXPathNode* insertion = mStartBuffer;
|
||||
|
||||
while (pos < length) {
|
||||
while (pos < length && !mMarks[pos]) {
|
||||
// delete unmarked
|
||||
mStart[pos].~txXPathNode();
|
||||
++pos;
|
||||
}
|
||||
// find chunk to move
|
||||
chunk = 0;
|
||||
while (pos < length && mMarks[pos]) {
|
||||
++pos;
|
||||
++chunk;
|
||||
}
|
||||
// move chunk
|
||||
if (chunk > 0) {
|
||||
memmove(insertion, mStart + pos - chunk,
|
||||
chunk * sizeof(txXPathNode));
|
||||
insertion += chunk;
|
||||
}
|
||||
}
|
||||
mStart = mStartBuffer;
|
||||
mEnd = insertion;
|
||||
delete [] mMarks;
|
||||
mMarks = nsnull;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
txNodeSet::clear()
|
||||
{
|
||||
while (mStart < mEnd) {
|
||||
mStart->~txXPathNode();
|
||||
++mStart;
|
||||
}
|
||||
#ifdef TX_DONT_RECYCLE_BUFFER
|
||||
if (mStartBuffer) {
|
||||
nsMemory::Free(mStartBuffer);
|
||||
mStartBuffer = mEndBuffer = nsnull;
|
||||
}
|
||||
#endif
|
||||
mStart = mEnd = mStartBuffer;
|
||||
delete [] mMarks;
|
||||
mMarks = nsnull;
|
||||
mDirection = kForward;
|
||||
}
|
||||
|
||||
PRInt32
|
||||
txNodeSet::indexOf(const txXPathNode& aNode) const
|
||||
{
|
||||
NS_ASSERTION(mDirection == kForward,
|
||||
"only append(aNode) is supported on reversed nodesets");
|
||||
|
||||
if (!mStart || mStart == mEnd) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
PRInt32 counter = 0;
|
||||
txXPathNode* pos = mStart;
|
||||
for (; pos < mEnd; ++counter, ++pos) {
|
||||
if (*pos == aNode) {
|
||||
return counter;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the Node at the specified position in this NodeSet.
|
||||
* @param aIndex the position of the Node to return
|
||||
* @return Node at specified position
|
||||
*/
|
||||
Node* txNodeSet::get(int aIndex) const
|
||||
const txXPathNode&
|
||||
txNodeSet::get(PRInt32 aIndex) const
|
||||
{
|
||||
NS_ASSERTION(aIndex >= 0 && aIndex < mElementCount,
|
||||
"invalid index in txNodeSet::get");
|
||||
if (aIndex < 0 || aIndex >= mElementCount)
|
||||
return 0;
|
||||
if (mDirection == kForward) {
|
||||
return mStart[aIndex];
|
||||
}
|
||||
|
||||
return mElements[aIndex];
|
||||
return mEnd[-aIndex - 1];
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the type of ExprResult represented
|
||||
* @return the type of ExprResult represented
|
||||
*/
|
||||
short txNodeSet::getResultType()
|
||||
short
|
||||
txNodeSet::getResultType()
|
||||
{
|
||||
return txAExprResult::NODESET;
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts this ExprResult to a Boolean (MBool) value
|
||||
* @return the Boolean value
|
||||
*/
|
||||
MBool txNodeSet::booleanValue()
|
||||
PRBool
|
||||
txNodeSet::booleanValue()
|
||||
{
|
||||
return mElementCount > 0;
|
||||
return !isEmpty();
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts this ExprResult to a Number (double) value
|
||||
* @return the Number value
|
||||
*/
|
||||
double txNodeSet::numberValue()
|
||||
double
|
||||
txNodeSet::numberValue()
|
||||
{
|
||||
nsAutoString str;
|
||||
stringValue(str);
|
||||
|
||||
return Double::toDouble(str);
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a String representation of this ExprResult
|
||||
* @param aStr the destination string to append the String representation to.
|
||||
*/
|
||||
void txNodeSet::stringValue(nsAString& aStr)
|
||||
void
|
||||
txNodeSet::stringValue(nsAString& aStr)
|
||||
{
|
||||
if (mElementCount > 0)
|
||||
XMLDOMUtils::getNodeValue(get(0), aStr);
|
||||
NS_ASSERTION(mDirection == kForward,
|
||||
"only append(aNode) is supported on reversed nodesets");
|
||||
if (isEmpty()) {
|
||||
return;
|
||||
}
|
||||
txXPathNodeUtils::appendNodeValue(get(0), aStr);
|
||||
}
|
||||
|
||||
nsAString*
|
||||
|
@ -398,89 +489,132 @@ txNodeSet::stringValuePointer()
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
/*
|
||||
* Makes sure that the mElements buffer contains at least aSize elements.
|
||||
* If a new allocation is required the elements are copied over to the new
|
||||
* buffer
|
||||
* @param aSize requested number of elements
|
||||
* @return true if allocation succeded, false on out of memory
|
||||
*/
|
||||
MBool txNodeSet::ensureSize(int aSize)
|
||||
PRBool txNodeSet::ensureGrowSize(PRInt32 aSize)
|
||||
{
|
||||
if (aSize <= mBufferSize)
|
||||
return MB_TRUE;
|
||||
// check if there is enough place in the buffer as is
|
||||
if (mDirection == kForward && aSize <= mEndBuffer - mEnd) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (mDirection == kReversed && aSize <= mStart - mStartBuffer) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// check if we just have to align mStart to have enough space
|
||||
PRInt32 oldSize = mEnd - mStart;
|
||||
PRInt32 oldLength = mEndBuffer - mStartBuffer;
|
||||
PRInt32 ensureSize = oldSize + aSize;
|
||||
if (ensureSize <= oldLength) {
|
||||
// just move the buffer
|
||||
txXPathNode* dest = mStartBuffer;
|
||||
if (mDirection == kReversed) {
|
||||
dest = mEndBuffer - oldSize;
|
||||
}
|
||||
memmove(dest, mStart, oldSize * sizeof(txXPathNode));
|
||||
mStart = dest;
|
||||
mEnd = dest + oldSize;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// This isn't 100% safe. But until someone manages to make a 1gig nodeset
|
||||
// it should be ok.
|
||||
int newSize = mBufferSize > kTxNodeSetMinSize ? mBufferSize :
|
||||
kTxNodeSetMinSize;
|
||||
while (newSize < aSize)
|
||||
newSize *= kTxNodeSetGrowFactor;
|
||||
PRInt32 newLength = PR_MAX(oldLength, kTxNodeSetMinSize);
|
||||
|
||||
Node** newArr = new Node*[newSize];
|
||||
if (!newArr)
|
||||
return MB_FALSE;
|
||||
|
||||
if (mElementCount)
|
||||
memcpy(newArr, mElements, mElementCount * sizeof(Node*));
|
||||
while (newLength < ensureSize) {
|
||||
newLength *= kTxNodeSetGrowFactor;
|
||||
}
|
||||
|
||||
delete [] mElements;
|
||||
mElements = newArr;
|
||||
mBufferSize = newSize;
|
||||
|
||||
return MB_TRUE;
|
||||
txXPathNode* newArr = NS_STATIC_CAST(txXPathNode*,
|
||||
nsMemory::Alloc(newLength *
|
||||
sizeof(txXPathNode)));
|
||||
if (!newArr) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
txXPathNode* dest = newArr;
|
||||
if (mDirection == kReversed) {
|
||||
dest += newLength - oldSize;
|
||||
}
|
||||
|
||||
if (oldSize > 0) {
|
||||
memcpy(dest, mStart, oldSize * sizeof(txXPathNode));
|
||||
}
|
||||
|
||||
if (mStartBuffer) {
|
||||
#ifdef DEBUG
|
||||
memset(mStartBuffer, 0,
|
||||
(mEndBuffer - mStartBuffer) * sizeof(txXPathNode));
|
||||
#endif
|
||||
nsMemory::Free(mStartBuffer);
|
||||
}
|
||||
|
||||
mStartBuffer = newArr;
|
||||
mEndBuffer = mStartBuffer + newLength;
|
||||
mStart = dest;
|
||||
mEnd = dest + oldSize;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds position in the mElements buffer where a node should be inserted
|
||||
* to keep the nodeset in document order. Searches the positions
|
||||
* aFirst-aLast, including both aFirst and aLast.
|
||||
* @param aNode Node to find insert position for
|
||||
* @param aFirst First index to search, this index will be searched
|
||||
* @param aLast Last index to search, this index will be searched
|
||||
* @param aNonDup Out-param. Set to true if the node should be inserted,
|
||||
* false if it already exists in the NodeSet.
|
||||
* @return The index where to insert the node. The node should be
|
||||
* inserted before the node at this index. This value is
|
||||
* always >= aFirst and <= aLast + 1. This value is always
|
||||
* set, even if aNode already exists in the NodeSet
|
||||
*/
|
||||
int txNodeSet::findPosition(Node* aNode, int aFirst,
|
||||
int aLast, MBool& aNonDup) const
|
||||
txXPathNode*
|
||||
txNodeSet::findPosition(const txXPathNode& aNode, txXPathNode* aFirst,
|
||||
txXPathNode* aLast, PRBool& aDupe) const
|
||||
{
|
||||
NS_ASSERTION(aNode, "missing node in txNodeSet::findPosition");
|
||||
NS_ASSERTION(aFirst <= aLast+1 && aLast < mElementCount,
|
||||
"bad position in txNodeSet::findPosition");
|
||||
|
||||
if (aLast - aFirst <= 1) {
|
||||
aDupe = PR_FALSE;
|
||||
if (aLast - aFirst <= 2) {
|
||||
// If we search 2 nodes or less there is no point in further divides
|
||||
int pos;
|
||||
for (pos = aFirst; pos <= aLast; ++pos) {
|
||||
int cmp = aNode->compareDocumentPosition(mElements[pos]);
|
||||
txXPathNode* pos = aFirst;
|
||||
for (; pos < aLast; ++pos) {
|
||||
PRIntn cmp = txXPathNodeUtils::comparePosition(aNode, *pos);
|
||||
if (cmp < 0) {
|
||||
aNonDup = MB_TRUE;
|
||||
return pos;
|
||||
}
|
||||
|
||||
if (cmp == 0) {
|
||||
aNonDup = MB_FALSE;
|
||||
aDupe = PR_TRUE;
|
||||
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
aNonDup = MB_TRUE;
|
||||
return pos;
|
||||
}
|
||||
|
||||
int midpos = (aFirst + aLast) / 2;
|
||||
int cmp = aNode->compareDocumentPosition(mElements[midpos]);
|
||||
|
||||
// (cannot add two pointers)
|
||||
txXPathNode* midpos = aFirst + (aLast - aFirst) / 2;
|
||||
PRIntn cmp = txXPathNodeUtils::comparePosition(aNode, *midpos);
|
||||
if (cmp == 0) {
|
||||
aNonDup = MB_FALSE;
|
||||
aDupe = PR_TRUE;
|
||||
|
||||
return midpos;
|
||||
}
|
||||
|
||||
if (cmp > 0)
|
||||
return findPosition(aNode, midpos + 1, aLast, aNonDup);
|
||||
if (cmp > 0) {
|
||||
return findPosition(aNode, midpos + 1, aLast, aDupe);
|
||||
}
|
||||
|
||||
return findPosition(aNode, aFirst, midpos - 1, aNonDup);
|
||||
// midpos excluded as end of range
|
||||
|
||||
return findPosition(aNode, aFirst, midpos, aDupe);
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
txNodeSet::copyElements(txXPathNode* aDest,
|
||||
const txXPathNode* aStart, const txXPathNode* aEnd)
|
||||
{
|
||||
const txXPathNode* pos = aStart;
|
||||
while (pos < aEnd) {
|
||||
new(aDest) txXPathNode(*pos);
|
||||
++aDest;
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
txNodeSet::transferElements(txXPathNode* aDest,
|
||||
const txXPathNode* aStart, const txXPathNode* aEnd)
|
||||
{
|
||||
memcpy(aDest, aStart, (aEnd - aStart) * sizeof(txXPathNode));
|
||||
}
|
||||
|
|
|
@ -27,183 +27,209 @@
|
|||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
/**
|
||||
* Implementation of an XPath NodeSet
|
||||
*/
|
||||
|
||||
#ifndef TRANSFRMX_NODESET_H
|
||||
#define TRANSFRMX_NODESET_H
|
||||
#ifndef txNodeSet_h__
|
||||
#define txNodeSet_h__
|
||||
|
||||
#include "ExprResult.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "txError.h"
|
||||
|
||||
class Node;
|
||||
#include "txXPathTreeWalker.h"
|
||||
|
||||
class txNodeSet : public txAExprResult
|
||||
{
|
||||
|
||||
public:
|
||||
// XXX TEMP
|
||||
txNodeSet();
|
||||
|
||||
txNodeSet(); // Not to be implemented
|
||||
|
||||
/*
|
||||
/**
|
||||
* Creates a new empty NodeSet
|
||||
*/
|
||||
txNodeSet(txResultRecycler* aRecycler);
|
||||
|
||||
/*
|
||||
* Creates a new NodeSet containing the supplied node
|
||||
/**
|
||||
* Creates a new NodeSet with one node.
|
||||
*/
|
||||
txNodeSet(Node* aNode, txResultRecycler* aRecycler);
|
||||
txNodeSet(const txXPathNode& aNode, txResultRecycler* aRecycler);
|
||||
|
||||
/*
|
||||
* Creates a new NodeSet, copying the Node references from the source
|
||||
* NodeSet
|
||||
/**
|
||||
* Creates a new txNodeSet, copying the node references from the source
|
||||
* NodeSet.
|
||||
*/
|
||||
txNodeSet(const txNodeSet& aSource, txResultRecycler* aRecycler);
|
||||
|
||||
/*
|
||||
* Destructor for NodeSet, will not delete referenced Nodes
|
||||
/**
|
||||
* Destructor for txNodeSet, deletes the nodes.
|
||||
*/
|
||||
virtual ~txNodeSet()
|
||||
{
|
||||
delete [] mElements;
|
||||
}
|
||||
virtual ~txNodeSet();
|
||||
|
||||
/*
|
||||
* Adds the specified Node to this NodeSet if it is not already in this
|
||||
* NodeSet. The node is inserted according to document order.
|
||||
* @param aNode the Node to add to the NodeSet
|
||||
/**
|
||||
* Adds the specified txXPathNode to this NodeSet if it is not already
|
||||
* in this NodeSet. The node is inserted according to document order.
|
||||
*
|
||||
* @param aNode the txXPathNode to add to the NodeSet
|
||||
* @return errorcode.
|
||||
*/
|
||||
nsresult add(Node* aNode);
|
||||
nsresult add(const txXPathNode& aNode);
|
||||
|
||||
/*
|
||||
/**
|
||||
* Adds the nodes in specified NodeSet to this NodeSet. The resulting
|
||||
* NodeSet is sorted in document order and does not contain any duplicate
|
||||
* nodes.
|
||||
*
|
||||
* @param aNodes the NodeSet to add, must be in document order.
|
||||
* @return errorcode.
|
||||
*/
|
||||
nsresult add(const txNodeSet* aNodes);
|
||||
nsresult add(const txNodeSet& aNodes);
|
||||
nsresult addAndTransfer(txNodeSet* aNodes);
|
||||
|
||||
/*
|
||||
/**
|
||||
* Append API
|
||||
* These functions should be used with care.
|
||||
* They are intended to be used when the caller assures that the resulting
|
||||
* NodeSet remains in document order.
|
||||
* Abuse will break document order, and cause errors in the result.
|
||||
* These functions are significantly faster than the add API, as no
|
||||
* Node::OrderInfo structs will be generated.
|
||||
* order info operations will be performed.
|
||||
*/
|
||||
|
||||
/*
|
||||
/**
|
||||
* Appends the specified Node to the end of this NodeSet
|
||||
* @param aNode the Node to append to the NodeSet
|
||||
* @return errorcode.
|
||||
*/
|
||||
nsresult append(Node* aNode);
|
||||
nsresult append(const txXPathNode& aNode);
|
||||
|
||||
/*
|
||||
/**
|
||||
* Appends the nodes in the specified NodeSet to the end of this NodeSet
|
||||
* @param aNodes the NodeSet to append to the NodeSet
|
||||
* @return errorcode.
|
||||
*/
|
||||
nsresult append(const txNodeSet* aNodes);
|
||||
nsresult append(const txNodeSet& aNodes);
|
||||
|
||||
/*
|
||||
* Reverse the order of the nodes.
|
||||
/**
|
||||
* API to implement reverse axes in LocationStep.
|
||||
*
|
||||
* Before adding nodes to the nodeset for a reversed axis, call
|
||||
* setReverse(). This will make the append(aNode) and get() methods treat
|
||||
* the nodeset as required. Do only call append(aNode), get(), mark()
|
||||
* and sweep() while the nodeset is reversed.
|
||||
* Afterwards, call unsetReverse(). The nodes are stored in document
|
||||
* order internally.
|
||||
*/
|
||||
void reverse();
|
||||
|
||||
/*
|
||||
* Removes all nodes from this nodeset
|
||||
*/
|
||||
void clear()
|
||||
void setReverse()
|
||||
{
|
||||
mElementCount = 0;
|
||||
mDirection = -1;
|
||||
}
|
||||
void unsetReverse()
|
||||
{
|
||||
mDirection = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* API to implement predicates in PredicateExpr
|
||||
*
|
||||
* mark(aIndex) marks the specified member of the nodeset.
|
||||
* sweep() clears all members of the nodeset that haven't been
|
||||
* marked before and clear the mMarks array.
|
||||
*/
|
||||
nsresult mark(PRInt32 aIndex);
|
||||
nsresult sweep();
|
||||
|
||||
/**
|
||||
* Removes all nodes from this nodeset
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Returns the index of the specified Node,
|
||||
* or -1 if the Node is not contained in the NodeSet
|
||||
* @param aNode the Node to get the index for
|
||||
* @return index of specified node or -1 if the node does not exist
|
||||
*/
|
||||
int indexOf(Node* aNode) const;
|
||||
PRInt32 indexOf(const txXPathNode& aNode) const;
|
||||
|
||||
/*
|
||||
/**
|
||||
* Returns true if the specified Node is contained in the set.
|
||||
* @param aNode the Node to search for
|
||||
* @return true if specified Node is contained in the NodeSet
|
||||
*/
|
||||
MBool contains(Node* aNode) const
|
||||
PRBool contains(const txXPathNode& aNode) const
|
||||
{
|
||||
return indexOf(aNode) >= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the Node at the specified position in this NodeSet.
|
||||
* @param aIndex the position of the Node to return
|
||||
* @return Node at specified position
|
||||
/**
|
||||
* Returns the Node at the specified node in this NodeSet.
|
||||
* @param aIndex the node of the Node to return
|
||||
* @return Node at specified node
|
||||
*/
|
||||
Node* get(int aIndex) const;
|
||||
const txXPathNode& get(PRInt32 aIndex) const;
|
||||
|
||||
/*
|
||||
/**
|
||||
* Returns true if there are no Nodes in the NodeSet.
|
||||
* @return true if there are no Nodes in the NodeSet.
|
||||
*/
|
||||
MBool isEmpty() const
|
||||
PRBool isEmpty() const
|
||||
{
|
||||
return mElementCount == 0;
|
||||
return mStart ? mStart == mEnd : PR_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Returns the number of elements in the NodeSet
|
||||
* @return the number of elements in the NodeSet
|
||||
*/
|
||||
int size() const
|
||||
PRInt32 size() const
|
||||
{
|
||||
return mElementCount;
|
||||
return mStart ? mEnd - mStart : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Virtual methods from ExprResult
|
||||
*/
|
||||
TX_DECL_EXPRRESULT
|
||||
|
||||
private:
|
||||
static void toString(const txNodeSet& aNodes, nsAString& aResult);
|
||||
|
||||
/*
|
||||
* Makes sure that the mElements buffer contains at least aSize elements.
|
||||
* If a new allocation is required the elements are copied over to the new
|
||||
* buffer
|
||||
* @param aSize requested number of elements
|
||||
* @return true if allocation succeded, false on out of memory
|
||||
/**
|
||||
* Ensure that this nodeset can take another aSize nodes.
|
||||
*
|
||||
* Changes mStart and mEnd as well as mBufferStart and mBufferEnd.
|
||||
*/
|
||||
MBool ensureSize(int aSize);
|
||||
PRBool ensureGrowSize(PRInt32 aSize);
|
||||
|
||||
/*
|
||||
* Finds position in the mElements buffer where a node should be inserted
|
||||
/**
|
||||
* Finds position in the buffer where a node should be inserted
|
||||
* to keep the nodeset in document order. Searches the positions
|
||||
* aFirst-aLast, including both aFirst and aLast.
|
||||
* @param aNode Node to find insert position for
|
||||
* @param aFirst First index to search, this index will be searched
|
||||
* @param aLast Last index to search, this index will be searched
|
||||
* @param aPos out-param. Will be set to the index where to insert the
|
||||
* node. The node should be inserted before the node at
|
||||
* this index. This value is always >= aFirst and
|
||||
* <= aLast + 1. This value is always set, even if aNode
|
||||
* already exists in the NodeSet.
|
||||
* @return true if the node should be inserted, false if it already exists
|
||||
* in the NodeSet
|
||||
* aFirst-aLast, including aFirst, but not aLast.
|
||||
* @param aNode Node to find insert position for.
|
||||
* @param aFirst First item of the search range, included.
|
||||
* @param aLast Last item of the search range, excluded.
|
||||
* @param aDupe out-param. Will be set to true if the node already
|
||||
* exists in the NodeSet, false if it should be
|
||||
* inserted.
|
||||
* @return pointer where to insert the node. The node should be inserted
|
||||
* before the given node. This value is always set, even if aNode
|
||||
* already exists in the NodeSet
|
||||
*/
|
||||
MBool findPosition(Node* aNode, int aFirst, int aLast, int& aPos) const;
|
||||
txXPathNode* findPosition(const txXPathNode& aNode,
|
||||
txXPathNode* aFirst,
|
||||
txXPathNode* aLast, PRBool& aDupe) const;
|
||||
|
||||
Node** mElements;
|
||||
int mBufferSize;
|
||||
int mElementCount;
|
||||
static void copyElements(txXPathNode* aDest, const txXPathNode* aStart,
|
||||
const txXPathNode* aEnd);
|
||||
static void transferElements(txXPathNode* aDest, const txXPathNode* aStart,
|
||||
const txXPathNode* aEnd);
|
||||
|
||||
typedef void (*transferOp) (txXPathNode* aDest, const txXPathNode* aStart,
|
||||
const txXPathNode* aEnd);
|
||||
nsresult add(const txNodeSet& aNodes, transferOp aTransfer);
|
||||
|
||||
txXPathNode *mStart, *mEnd, *mStartBuffer, *mEndBuffer;
|
||||
PRInt32 mDirection;
|
||||
// used for mark() and sweep() in predicates
|
||||
PRPackedBool* mMarks;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
#include "txNodeSetContext.h"
|
||||
#include "txNodeSet.h"
|
||||
|
||||
Node* txNodeSetContext::getContextNode()
|
||||
const txXPathNode& txNodeSetContext::getContextNode()
|
||||
{
|
||||
return mContextSet->get(mPosition - 1);
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ nsresult txNodeSetContext::getVariable(PRInt32 aNamespace, nsIAtom* aLName,
|
|||
return mInner->getVariable(aNamespace, aLName, aResult);
|
||||
}
|
||||
|
||||
MBool txNodeSetContext::isStripSpaceAllowed(Node* aNode)
|
||||
MBool txNodeSetContext::isStripSpaceAllowed(const txXPathNode& aNode)
|
||||
{
|
||||
NS_ASSERTION(mInner, "mInner is null!!!");
|
||||
return mInner->isStripSpaceAllowed(aNode);
|
||||
|
|
|
@ -33,11 +33,11 @@
|
|||
*/
|
||||
|
||||
#include "FunctionLib.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "txNodeSet.h"
|
||||
#include "txAtoms.h"
|
||||
#include "txIXPathContext.h"
|
||||
#include "txTokenizer.h"
|
||||
#include "XMLDOMUtils.h"
|
||||
#ifndef TX_EXE
|
||||
#include "nsIDOMNode.h"
|
||||
#endif
|
||||
|
@ -92,12 +92,7 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
Document* contextDoc = 0;
|
||||
Node* contextNode = aContext->getContextNode();
|
||||
if (contextNode->getNodeType() == Node::DOCUMENT_NODE)
|
||||
contextDoc = (Document*)contextNode;
|
||||
else
|
||||
contextDoc = contextNode->getOwnerDocument();
|
||||
txXPathTreeWalker walker(aContext->getContextNode());
|
||||
|
||||
if (exprResult->getResultType() == txAExprResult::NODESET) {
|
||||
txNodeSet* nodes = NS_STATIC_CAST(txNodeSet*,
|
||||
|
@ -106,13 +101,12 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
PRInt32 i;
|
||||
for (i = 0; i < nodes->size(); ++i) {
|
||||
nsAutoString idList;
|
||||
XMLDOMUtils::getNodeValue(nodes->get(i), idList);
|
||||
txXPathNodeUtils::appendNodeValue(nodes->get(i), idList);
|
||||
txTokenizer tokenizer(idList);
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
Node* idNode =
|
||||
contextDoc->getElementById(tokenizer.nextToken());
|
||||
if (idNode)
|
||||
resultSet->add(idNode);
|
||||
if (walker.moveToElementById(tokenizer.nextToken())) {
|
||||
resultSet->add(walker.getCurrentPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,10 +115,9 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
exprResult->stringValue(idList);
|
||||
txTokenizer tokenizer(idList);
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
Node* idNode =
|
||||
contextDoc->getElementById(tokenizer.nextToken());
|
||||
if (idNode)
|
||||
resultSet->add(idNode);
|
||||
if (walker.moveToElementById(tokenizer.nextToken())) {
|
||||
resultSet->add(walker.getCurrentPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,10 +142,9 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
|
||||
}
|
||||
|
||||
Node* node = 0;
|
||||
// Check for optional arg
|
||||
nsRefPtr<txNodeSet> nodes;
|
||||
if (iter.hasNext()) {
|
||||
nsRefPtr<txNodeSet> nodes;
|
||||
rv = evaluateToNodeSet((Expr*)iter.next(), aContext,
|
||||
getter_AddRefs(nodes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -162,12 +154,10 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
|
||||
return NS_OK;
|
||||
}
|
||||
node = nodes->get(0);
|
||||
}
|
||||
else {
|
||||
node = aContext->getContextNode();
|
||||
}
|
||||
|
||||
const txXPathNode& node = nodes ? nodes->get(0) :
|
||||
aContext->getContextNode();
|
||||
switch (mType) {
|
||||
case LOCAL_NAME:
|
||||
{
|
||||
|
@ -176,23 +166,8 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aResult = strRes;
|
||||
#ifdef TX_EXE
|
||||
nsCOMPtr<nsIAtom> localNameAtom;
|
||||
node->getLocalName(getter_AddRefs(localNameAtom));
|
||||
if (localNameAtom) {
|
||||
// Node has a localName
|
||||
localNameAtom->ToString(strRes->mValue);
|
||||
}
|
||||
#else
|
||||
// The mozilla HTML-elements returns different casing for
|
||||
// the localName-atom and .localName. Once we have a
|
||||
// treeWalker it should have a getLocalName(nsAString&)
|
||||
// function.
|
||||
nsCOMPtr<nsIDOMNode> mozNode =
|
||||
do_QueryInterface(node->getNSObj());
|
||||
NS_ASSERTION(mozNode, "wrapper doesn't wrap a nsIDOMNode");
|
||||
mozNode->GetLocalName(strRes->mValue);
|
||||
#endif
|
||||
txXPathNodeUtils::getLocalName(node, strRes->mValue);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
case NAMESPACE_URI:
|
||||
|
@ -202,16 +177,16 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aResult = strRes;
|
||||
node->getNamespaceURI(strRes->mValue);
|
||||
txXPathNodeUtils::getNamespaceURI(node, strRes->mValue);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
case NAME:
|
||||
{
|
||||
switch (node->getNodeType()) {
|
||||
case Node::ATTRIBUTE_NODE:
|
||||
case Node::ELEMENT_NODE:
|
||||
case Node::PROCESSING_INSTRUCTION_NODE:
|
||||
switch (txXPathNodeUtils::getNodeType(node)) {
|
||||
case txXPathNodeType::ATTRIBUTE_NODE:
|
||||
case txXPathNodeType::ELEMENT_NODE:
|
||||
case txXPathNodeType::PROCESSING_INSTRUCTION_NODE:
|
||||
// XXX Namespace: namespaces have a name
|
||||
{
|
||||
StringResult* strRes = nsnull;
|
||||
|
@ -219,7 +194,7 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aResult = strRes;
|
||||
node->getNodeName(strRes->mValue);
|
||||
txXPathNodeUtils::getNodeName(node, strRes->mValue);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "Expr.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "txIXPathContext.h"
|
||||
#include "txXPathTreeWalker.h"
|
||||
|
||||
/*
|
||||
* Creates a new txNodeTypeTest of the given type
|
||||
|
@ -44,34 +45,29 @@ void txNodeTypeTest::setNodeName(const nsAString& aName)
|
|||
mNodeName = do_GetAtom(aName);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determines whether this txNodeTest matches the given node
|
||||
*/
|
||||
MBool txNodeTypeTest::matches(Node* aNode, txIMatchContext* aContext)
|
||||
PRBool txNodeTypeTest::matches(const txXPathNode& aNode,
|
||||
txIMatchContext* aContext)
|
||||
{
|
||||
if (!aNode)
|
||||
return MB_FALSE;
|
||||
|
||||
Node::NodeType type = (Node::NodeType)aNode->getNodeType();
|
||||
PRUint16 type = txXPathNodeUtils::getNodeType(aNode);
|
||||
|
||||
switch (mNodeType) {
|
||||
case COMMENT_TYPE:
|
||||
return type == Node::COMMENT_NODE;
|
||||
return type == txXPathNodeType::COMMENT_NODE;
|
||||
case TEXT_TYPE:
|
||||
return (type == Node::TEXT_NODE ||
|
||||
type == Node::CDATA_SECTION_NODE) &&
|
||||
return (type == txXPathNodeType::TEXT_NODE ||
|
||||
type == txXPathNodeType::CDATA_SECTION_NODE) &&
|
||||
!aContext->isStripSpaceAllowed(aNode);
|
||||
case PI_TYPE:
|
||||
if (type == Node::PROCESSING_INSTRUCTION_NODE) {
|
||||
if (type == txXPathNodeType::PROCESSING_INSTRUCTION_NODE) {
|
||||
nsCOMPtr<nsIAtom> localName;
|
||||
return !mNodeName ||
|
||||
(aNode->getLocalName(getter_AddRefs(localName)) &&
|
||||
((localName = txXPathNodeUtils::getLocalName(aNode)) &&
|
||||
localName == mNodeName);
|
||||
}
|
||||
return MB_FALSE;
|
||||
case NODE_TYPE:
|
||||
return ((type != Node::TEXT_NODE &&
|
||||
type != Node::CDATA_SECTION_NODE) ||
|
||||
return ((type != txXPathNodeType::TEXT_NODE &&
|
||||
type != txXPathNodeType::CDATA_SECTION_NODE) ||
|
||||
!aContext->isStripSpaceAllowed(aNode));
|
||||
}
|
||||
return MB_TRUE;
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include "txNodeSet.h"
|
||||
#include "txAtoms.h"
|
||||
#include "txIXPathContext.h"
|
||||
#include "XMLDOMUtils.h"
|
||||
|
||||
/*
|
||||
* Creates a NumberFunctionCall of the given type
|
||||
|
@ -121,7 +120,7 @@ NumberFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
PRInt32 i;
|
||||
for (i = 0; i < nodes->size(); ++i) {
|
||||
nsAutoString resultStr;
|
||||
XMLDOMUtils::getNodeValue(nodes->get(i), resultStr);
|
||||
txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr);
|
||||
res += Double::toDouble(resultStr);
|
||||
}
|
||||
return aContext->recycler()->getNumberResult(res, aResult);
|
||||
|
@ -134,8 +133,8 @@ NumberFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
}
|
||||
else {
|
||||
nsAutoString resultStr;
|
||||
XMLDOMUtils::getNodeValue(aContext->getContextNode(),
|
||||
resultStr);
|
||||
txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
|
||||
resultStr);
|
||||
res = Double::toDouble(resultStr);
|
||||
}
|
||||
return aContext->recycler()->getNumberResult(res, aResult);
|
||||
|
|
|
@ -109,14 +109,14 @@ PathExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
txNodeSetContext eContext(nodes, aContext);
|
||||
while (eContext.hasNext()) {
|
||||
eContext.next();
|
||||
Node* node = eContext.getContextNode();
|
||||
|
||||
|
||||
nsRefPtr<txNodeSet> resNodes;
|
||||
if (pxi->pathOp == DESCENDANT_OP) {
|
||||
rv = aContext->recycler()->getNodeSet(getter_AddRefs(resNodes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = evalDescendants(pxi->expr, node, &eContext, resNodes);
|
||||
rv = evalDescendants(pxi->expr, eContext.getContextNode(),
|
||||
&eContext, resNodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else {
|
||||
|
@ -141,7 +141,12 @@ PathExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
getNonSharedNodeSet(oldSet, getter_AddRefs(tmpNodes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
tmpNodes->add(resNodes);
|
||||
oldSet.swap(resNodes);
|
||||
rv = aContext->recycler()->
|
||||
getNonSharedNodeSet(oldSet, getter_AddRefs(resNodes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
tmpNodes->addAndTransfer(resNodes);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -165,8 +170,8 @@ PathExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
* all nodes that match the Expr
|
||||
**/
|
||||
nsresult
|
||||
PathExpr::evalDescendants(Expr* aStep, Node* aNode, txIMatchContext* aContext,
|
||||
txNodeSet* resNodes)
|
||||
PathExpr::evalDescendants(Expr* aStep, const txXPathNode& aNode,
|
||||
txIMatchContext* aContext, txNodeSet* resNodes)
|
||||
{
|
||||
txSingleNodeContext eContext(aNode, aContext);
|
||||
nsRefPtr<txAExprResult> res;
|
||||
|
@ -177,23 +182,34 @@ PathExpr::evalDescendants(Expr* aStep, Node* aNode, txIMatchContext* aContext,
|
|||
//XXX ErrorReport: report nonnodeset error
|
||||
return NS_ERROR_XSLT_NODESET_EXPECTED;
|
||||
}
|
||||
resNodes->add(NS_STATIC_CAST(txNodeSet*, NS_STATIC_CAST(txAExprResult*,
|
||||
res)));
|
||||
|
||||
txNodeSet* oldSet = NS_STATIC_CAST(txNodeSet*,
|
||||
NS_STATIC_CAST(txAExprResult*, res));
|
||||
nsRefPtr<txNodeSet> newSet;
|
||||
rv = aContext->recycler()->getNonSharedNodeSet(oldSet,
|
||||
getter_AddRefs(newSet));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
resNodes->addAndTransfer(newSet);
|
||||
|
||||
MBool filterWS = aContext->isStripSpaceAllowed(aNode);
|
||||
|
||||
Node* child = aNode->getFirstChild();
|
||||
while (child) {
|
||||
txXPathTreeWalker walker(aNode);
|
||||
if (!walker.moveToFirstChild()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
do {
|
||||
if (!(filterWS &&
|
||||
(child->getNodeType() == Node::TEXT_NODE ||
|
||||
child->getNodeType() == Node::CDATA_SECTION_NODE) &&
|
||||
XMLUtils::isWhitespace(child))) {
|
||||
rv = evalDescendants(aStep, child, aContext, resNodes);
|
||||
(walker.getNodeType() == txXPathNodeType::TEXT_NODE ||
|
||||
walker.getNodeType() == txXPathNodeType::CDATA_SECTION_NODE) &&
|
||||
txXPathNodeUtils::isWhitespace(walker.getCurrentPosition()))) {
|
||||
rv = evalDescendants(aStep, walker.getCurrentPosition(), aContext,
|
||||
resNodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
child = child->getNextSibling();
|
||||
}
|
||||
|
||||
} while (walker.moveToNextSibling());
|
||||
|
||||
return NS_OK;
|
||||
} //-- evalDescendants
|
||||
|
||||
|
|
|
@ -67,10 +67,8 @@ PredicateList::evaluatePredicates(txNodeSet* nodes,
|
|||
txIMatchContext* aContext)
|
||||
{
|
||||
NS_ASSERTION(nodes, "called evaluatePredicates with NULL NodeSet");
|
||||
nsRefPtr<txNodeSet> newNodes;
|
||||
nsresult rv = aContext->recycler()->getNodeSet(getter_AddRefs(newNodes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
txListIterator iter(&predicates);
|
||||
while (iter.hasNext() && !nodes->isEmpty()) {
|
||||
Expr* expr = (Expr*)iter.next();
|
||||
|
@ -80,31 +78,28 @@ PredicateList::evaluatePredicates(txNodeSet* nodes,
|
|||
* or, if the result is a number, add the node with the right
|
||||
* position
|
||||
*/
|
||||
newNodes->clear();
|
||||
PRInt32 index = 0;
|
||||
while (predContext.hasNext()) {
|
||||
predContext.next();
|
||||
nsRefPtr<txAExprResult> exprResult;
|
||||
rv = expr->evaluate(&predContext, getter_AddRefs(exprResult));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
switch(exprResult->getResultType()) {
|
||||
case txAExprResult::NUMBER:
|
||||
// handle default, [position() == numberValue()]
|
||||
if ((double)predContext.position() ==
|
||||
exprResult->numberValue())
|
||||
newNodes->append(predContext.getContextNode());
|
||||
break;
|
||||
default:
|
||||
if (exprResult->booleanValue())
|
||||
newNodes->append(predContext.getContextNode());
|
||||
break;
|
||||
// handle default, [position() == numberValue()]
|
||||
if (exprResult->getResultType() == txAExprResult::NUMBER) {
|
||||
if ((double)predContext.position() == exprResult->numberValue()) {
|
||||
nodes->mark(index);
|
||||
}
|
||||
}
|
||||
else if (exprResult->booleanValue()) {
|
||||
nodes->mark(index);
|
||||
}
|
||||
++index;
|
||||
}
|
||||
// Move new NodeSet to the current one
|
||||
nodes->clear();
|
||||
nodes->append(newNodes);
|
||||
// sweep the non-marked nodes
|
||||
nodes->sweep();
|
||||
}
|
||||
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
#include "Expr.h"
|
||||
#include "txNodeSet.h"
|
||||
#include "XMLDOMUtils.h"
|
||||
#include "txIXPathContext.h"
|
||||
|
||||
/**
|
||||
|
@ -58,7 +57,8 @@ RelationalExpr::compareResults(txIEvalContext* aContext, txAExprResult* aLeft,
|
|||
PRInt32 i;
|
||||
for (i = 0; i < nodeSet->size(); ++i) {
|
||||
strResult->mValue.Truncate();
|
||||
XMLDOMUtils::getNodeValue(nodeSet->get(i), strResult->mValue);
|
||||
txXPathNodeUtils::appendNodeValue(nodeSet->get(i),
|
||||
strResult->mValue);
|
||||
if (compareResults(aContext, strResult, aRight)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
@ -82,7 +82,8 @@ RelationalExpr::compareResults(txIEvalContext* aContext, txAExprResult* aLeft,
|
|||
PRInt32 i;
|
||||
for (i = 0; i < nodeSet->size(); ++i) {
|
||||
strResult->mValue.Truncate();
|
||||
XMLDOMUtils::getNodeValue(nodeSet->get(i), strResult->mValue);
|
||||
txXPathNodeUtils::appendNodeValue(nodeSet->get(i),
|
||||
strResult->mValue);
|
||||
if (compareResults(aContext, aLeft, strResult)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
@ -153,20 +154,27 @@ RelationalExpr::compareResults(txIEvalContext* aContext, txAExprResult* aLeft,
|
|||
|
||||
switch (mOp) {
|
||||
case LESS_THAN:
|
||||
{
|
||||
return leftDbl < rightDbl;
|
||||
|
||||
}
|
||||
case LESS_OR_EQUAL:
|
||||
{
|
||||
return leftDbl <= rightDbl;
|
||||
|
||||
case GREATER_THAN :
|
||||
}
|
||||
case GREATER_THAN:
|
||||
{
|
||||
return leftDbl > rightDbl;
|
||||
|
||||
}
|
||||
case GREATER_OR_EQUAL:
|
||||
{
|
||||
return leftDbl >= rightDbl;
|
||||
}
|
||||
default:
|
||||
{
|
||||
NS_NOTREACHED("We should have caught all cases");
|
||||
}
|
||||
}
|
||||
|
||||
NS_NOTREACHED("We should have caught all cases");
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -203,7 +203,7 @@ txResultRecycler::getNodeSet(txNodeSet* aNodeSet, txNodeSet** aResult)
|
|||
else {
|
||||
*aResult = NS_STATIC_CAST(txNodeSet*, mNodeSetResults.pop());
|
||||
(*aResult)->clear();
|
||||
(*aResult)->append(aNodeSet);
|
||||
(*aResult)->append(*aNodeSet);
|
||||
(*aResult)->mRecycler = this;
|
||||
}
|
||||
NS_ADDREF(*aResult);
|
||||
|
@ -212,7 +212,7 @@ txResultRecycler::getNodeSet(txNodeSet* aNodeSet, txNodeSet** aResult)
|
|||
}
|
||||
|
||||
nsresult
|
||||
txResultRecycler::getNodeSet(Node* aNode, txAExprResult** aResult)
|
||||
txResultRecycler::getNodeSet(const txXPathNode& aNode, txAExprResult** aResult)
|
||||
{
|
||||
if (mNodeSetResults.isEmpty()) {
|
||||
*aResult = new txNodeSet(aNode, this);
|
||||
|
@ -231,7 +231,7 @@ txResultRecycler::getNodeSet(Node* aNode, txAExprResult** aResult)
|
|||
}
|
||||
|
||||
nsresult
|
||||
txResultRecycler::getNodeSet(Node* aNode, txNodeSet** aResult)
|
||||
txResultRecycler::getNodeSet(const txXPathNode& aNode, txNodeSet** aResult)
|
||||
{
|
||||
if (mNodeSetResults.isEmpty()) {
|
||||
*aResult = new txNodeSet(aNode, this);
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
class txAExprResult;
|
||||
class StringResult;
|
||||
class txNodeSet;
|
||||
class Node;
|
||||
class txXPathNode;
|
||||
class NumberResult;
|
||||
class BooleanResult;
|
||||
|
||||
|
@ -82,8 +82,8 @@ public:
|
|||
nsresult getStringResult(const nsAString& aValue, txAExprResult** aResult);
|
||||
nsresult getNodeSet(txNodeSet** aResult);
|
||||
nsresult getNodeSet(txNodeSet* aNodeSet, txNodeSet** aResult);
|
||||
nsresult getNodeSet(Node* aNode, txAExprResult** aResult);
|
||||
nsresult getNodeSet(Node* aNode, txNodeSet** aResult);
|
||||
nsresult getNodeSet(const txXPathNode& aNode, txAExprResult** aResult);
|
||||
nsresult getNodeSet(const txXPathNode& aNode, txNodeSet** aResult);
|
||||
nsresult getNumberResult(double aValue, txAExprResult** aResult);
|
||||
|
||||
/**
|
||||
|
|
|
@ -45,12 +45,21 @@ RootExpr::RootExpr(MBool aSerialize) {
|
|||
nsresult
|
||||
RootExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
||||
{
|
||||
Node* context = aContext->getContextNode();
|
||||
if (context->getNodeType() != Node::DOCUMENT_NODE) {
|
||||
context = context->getOwnerDocument();
|
||||
const txXPathNode& context = aContext->getContextNode();
|
||||
nsAutoPtr<txXPathNode> document(txXPathNodeUtils::getDocument(context));
|
||||
if (!document) {
|
||||
nsRefPtr<txNodeSet> nodes;
|
||||
aContext->recycler()->getNodeSet(getter_AddRefs(nodes));
|
||||
if (!nodes) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
NS_ADDREF(*aResult = nodes);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return aContext->recycler()->getNodeSet(context, aResult);
|
||||
return aContext->recycler()->getNodeSet(*document, aResult);
|
||||
} //-- evaluate
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,11 +44,11 @@
|
|||
class txSingleNodeContext : public txIEvalContext
|
||||
{
|
||||
public:
|
||||
txSingleNodeContext(Node* aContextNode, txIMatchContext* aContext)
|
||||
txSingleNodeContext(const txXPathNode& aContextNode,
|
||||
txIMatchContext* aContext)
|
||||
: mNode(aContextNode),
|
||||
mInner(aContext)
|
||||
{
|
||||
NS_ASSERTION(aContextNode, "context node must be given");
|
||||
NS_ASSERTION(aContext, "txIMatchContext must be given");
|
||||
}
|
||||
~txSingleNodeContext()
|
||||
|
@ -61,7 +61,7 @@ public:
|
|||
return mInner->getVariable(aNamespace, aLName, aResult);
|
||||
}
|
||||
|
||||
MBool isStripSpaceAllowed(Node* aNode)
|
||||
MBool isStripSpaceAllowed(const txXPathNode& aNode)
|
||||
{
|
||||
NS_ASSERTION(mInner, "mInner is null!!!");
|
||||
return mInner->isStripSpaceAllowed(aNode);
|
||||
|
@ -91,7 +91,7 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
Node* getContextNode()
|
||||
const txXPathNode& getContextNode()
|
||||
{
|
||||
return mNode;
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
Node* mNode;
|
||||
const txXPathNode& mNode;
|
||||
txIMatchContext* mInner;
|
||||
};
|
||||
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
#include "FunctionLib.h"
|
||||
#include "txAtoms.h"
|
||||
#include "txIXPathContext.h"
|
||||
#include "XMLDOMUtils.h"
|
||||
#include "XMLUtils.h"
|
||||
#include "txXPathTreeWalker.h"
|
||||
#include <math.h>
|
||||
#include "nsReadableUtils.h"
|
||||
|
||||
|
@ -105,8 +105,8 @@ StringFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
if (iter.hasNext())
|
||||
evaluateToString((Expr*)iter.next(), aContext, resultStr);
|
||||
else
|
||||
XMLDOMUtils::getNodeValue(aContext->getContextNode(),
|
||||
resultStr);
|
||||
txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
|
||||
resultStr);
|
||||
|
||||
nsRefPtr<StringResult> strRes;
|
||||
rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
|
||||
|
@ -164,8 +164,8 @@ StringFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
if (iter.hasNext())
|
||||
evaluateToString((Expr*)iter.next(), aContext, resultStr);
|
||||
else
|
||||
XMLDOMUtils::getNodeValue(aContext->getContextNode(),
|
||||
resultStr);
|
||||
txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
|
||||
resultStr);
|
||||
rv = aContext->recycler()->getNumberResult(resultStr.Length(),
|
||||
aResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -280,7 +280,12 @@ StringFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
|
||||
nsAutoString src;
|
||||
evaluateToString((Expr*)iter.next(), aContext, src);
|
||||
if (src.IsEmpty()) {
|
||||
aContext->recycler()->getEmptyStringResult(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<StringResult> strRes;
|
||||
rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -318,8 +323,8 @@ StringFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
if (iter.hasNext())
|
||||
evaluateToString((Expr*)iter.next(), aContext, strRes->mValue);
|
||||
else
|
||||
XMLDOMUtils::getNodeValue(aContext->getContextNode(),
|
||||
strRes->mValue);
|
||||
txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
|
||||
strRes->mValue);
|
||||
*aResult = strRes;
|
||||
NS_ADDREF(*aResult);
|
||||
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
*/
|
||||
|
||||
#include "Expr.h"
|
||||
#include "txNodeSet.h"
|
||||
#include "txIXPathContext.h"
|
||||
#include "txNodeSet.h"
|
||||
|
||||
//-------------/
|
||||
//- UnionExpr -/
|
||||
|
@ -93,8 +93,16 @@ UnionExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
//XXX ErrorReport: report nonnodeset error
|
||||
return NS_ERROR_XSLT_NODESET_EXPECTED;
|
||||
}
|
||||
rv = nodes->add(NS_STATIC_CAST(txNodeSet*, NS_STATIC_CAST(txAExprResult*,
|
||||
exprResult)));
|
||||
|
||||
nsRefPtr<txNodeSet> resultSet, ownedSet;
|
||||
resultSet = NS_STATIC_CAST(txNodeSet*,
|
||||
NS_STATIC_CAST(txAExprResult*, exprResult));
|
||||
exprResult = nsnull;
|
||||
rv = aContext->recycler()->
|
||||
getNonSharedNodeSet(resultSet, getter_AddRefs(ownedSet));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = nodes->addAndTransfer(ownedSet);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,9 +38,9 @@
|
|||
|
||||
#include "txAtoms.h"
|
||||
#include "txIXPathContext.h"
|
||||
#include "XMLDOMUtils.h"
|
||||
#include "XSLTFunctions.h"
|
||||
#include "txExecutionState.h"
|
||||
#include "txURIUtils.h"
|
||||
|
||||
/*
|
||||
* Creates a new DocumentFunctionCall.
|
||||
|
@ -50,6 +50,43 @@ DocumentFunctionCall::DocumentFunctionCall(const nsAString& aBaseURI)
|
|||
{
|
||||
}
|
||||
|
||||
static void
|
||||
retrieveNode(txExecutionState* aExecutionState, const nsAString& aUri,
|
||||
const nsAString& aBaseUri, txNodeSet* aNodeSet)
|
||||
{
|
||||
nsAutoString absUrl;
|
||||
URIUtils::resolveHref(aUri, aBaseUri, absUrl);
|
||||
|
||||
PRInt32 hash = absUrl.RFindChar(PRUnichar('#'));
|
||||
PRUint32 urlEnd, fragStart, fragEnd;
|
||||
if (hash == kNotFound) {
|
||||
urlEnd = absUrl.Length();
|
||||
fragStart = 0;
|
||||
fragEnd = 0;
|
||||
}
|
||||
else {
|
||||
urlEnd = hash;
|
||||
fragStart = hash + 1;
|
||||
fragEnd = absUrl.Length();
|
||||
}
|
||||
|
||||
nsDependentSubstring docUrl(absUrl, 0, urlEnd);
|
||||
nsDependentSubstring frag(absUrl, fragStart, fragEnd);
|
||||
|
||||
const txXPathNode* loadNode = aExecutionState->retrieveDocument(docUrl);
|
||||
if (loadNode) {
|
||||
if (frag.IsEmpty()) {
|
||||
aNodeSet->add(*loadNode);
|
||||
}
|
||||
else {
|
||||
txXPathTreeWalker walker(*loadNode);
|
||||
if (walker.moveToElementById(frag)) {
|
||||
aNodeSet->add(walker.getCurrentPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluates this Expr based on the given context node and processor state
|
||||
* NOTE: the implementation is incomplete since it does not make use of the
|
||||
|
@ -97,7 +134,7 @@ DocumentFunctionCall::evaluate(txIEvalContext* aContext,
|
|||
baseURISet = MB_TRUE;
|
||||
|
||||
if (!nodeSet2->isEmpty()) {
|
||||
nodeSet2->get(0)->getBaseURI(baseURI);
|
||||
txXPathNodeUtils::getBaseURI(nodeSet2->get(0), baseURI);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,18 +145,15 @@ DocumentFunctionCall::evaluate(txIEvalContext* aContext,
|
|||
exprResult1));
|
||||
PRInt32 i;
|
||||
for (i = 0; i < nodeSet1->size(); ++i) {
|
||||
Node* node = nodeSet1->get(i);
|
||||
const txXPathNode& node = nodeSet1->get(i);
|
||||
nsAutoString uriStr;
|
||||
XMLDOMUtils::getNodeValue(node, uriStr);
|
||||
txXPathNodeUtils::appendNodeValue(node, uriStr);
|
||||
if (!baseURISet) {
|
||||
// if the second argument wasn't specified, use
|
||||
// the baseUri of node itself
|
||||
node->getBaseURI(baseURI);
|
||||
}
|
||||
Node* loadNode = es->retrieveDocument(uriStr, baseURI);
|
||||
if (loadNode) {
|
||||
nodeSet->add(loadNode);
|
||||
txXPathNodeUtils::getBaseURI(node, baseURI);
|
||||
}
|
||||
retrieveNode(es, uriStr, baseURI, nodeSet);
|
||||
}
|
||||
|
||||
NS_ADDREF(*aResult = nodeSet);
|
||||
|
@ -130,11 +164,8 @@ DocumentFunctionCall::evaluate(txIEvalContext* aContext,
|
|||
// The first argument is not a NodeSet
|
||||
nsAutoString uriStr;
|
||||
exprResult1->stringValue(uriStr);
|
||||
nsAString* base = baseURISet ? &baseURI : &mBaseURI;
|
||||
Node* loadNode = es->retrieveDocument(uriStr, *base);
|
||||
if (loadNode) {
|
||||
nodeSet->add(loadNode);
|
||||
}
|
||||
const nsAString* base = baseURISet ? &baseURI : &mBaseURI;
|
||||
retrieveNode(es, uriStr, *base, nodeSet);
|
||||
|
||||
NS_ADDREF(*aResult = nodeSet);
|
||||
|
||||
|
|
|
@ -53,53 +53,41 @@
|
|||
|
||||
const PRInt32 txExecutionState::kMaxRecursionDepth = 20000;
|
||||
|
||||
DHASH_WRAPPER(txLoadedDocumentsBase, txLoadedDocumentEntry, nsAString&)
|
||||
|
||||
nsresult txLoadedDocumentsHash::init(Document* aSourceDocument)
|
||||
nsresult txLoadedDocumentsHash::init(txXPathNode* aSourceDocument)
|
||||
{
|
||||
nsresult rv = Init(8);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mSourceDocument = aSourceDocument;
|
||||
Add(mSourceDocument);
|
||||
|
||||
nsAutoString baseURI;
|
||||
txXPathNodeUtils::getBaseURI(*mSourceDocument, baseURI);
|
||||
|
||||
txLoadedDocumentEntry* entry = PutEntry(baseURI);
|
||||
if (!entry) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
entry->mDocument = mSourceDocument;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
txLoadedDocumentsHash::~txLoadedDocumentsHash()
|
||||
{
|
||||
if (!mHashTable.ops) {
|
||||
if (!IsInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString baseURI;
|
||||
mSourceDocument->getBaseURI(baseURI);
|
||||
txXPathNodeUtils::getBaseURI(*mSourceDocument, baseURI);
|
||||
|
||||
txLoadedDocumentEntry* entry = GetEntry(baseURI);
|
||||
if (entry) {
|
||||
entry->mDocument = nsnull;
|
||||
delete entry->mDocument.forget();
|
||||
}
|
||||
}
|
||||
|
||||
void txLoadedDocumentsHash::Add(Document* aDocument)
|
||||
{
|
||||
nsAutoString baseURI;
|
||||
aDocument->getBaseURI(baseURI);
|
||||
txLoadedDocumentEntry* entry = AddEntry(baseURI);
|
||||
if (entry) {
|
||||
entry->mDocument = aDocument;
|
||||
}
|
||||
}
|
||||
|
||||
Document* txLoadedDocumentsHash::Get(const nsAString& aURI)
|
||||
{
|
||||
txLoadedDocumentEntry* entry = GetEntry(aURI);
|
||||
if (entry) {
|
||||
return entry->mDocument;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
txExecutionState::txExecutionState(txStylesheet* aStylesheet)
|
||||
: mStylesheet(aStylesheet),
|
||||
mNextInstruction(nsnull),
|
||||
|
@ -110,7 +98,7 @@ txExecutionState::txExecutionState(txStylesheet* aStylesheet)
|
|||
mTemplateRuleCount(0),
|
||||
mEvalContext(nsnull),
|
||||
mInitialEvalContext(nsnull),
|
||||
mRTFDocument(nsnull),
|
||||
// mRTFDocument(nsnull),
|
||||
mGlobalParams(nsnull),
|
||||
mKeyHash(aStylesheet->getKeyMap())
|
||||
{
|
||||
|
@ -121,7 +109,7 @@ txExecutionState::~txExecutionState()
|
|||
delete mResultHandler;
|
||||
delete mLocalVariables;
|
||||
delete mEvalContext;
|
||||
delete mRTFDocument;
|
||||
// delete mRTFDocument;
|
||||
|
||||
PRInt32 i;
|
||||
for (i = 0; i < mTemplateRuleCount; ++i) {
|
||||
|
@ -154,7 +142,7 @@ txExecutionState::~txExecutionState()
|
|||
}
|
||||
|
||||
nsresult
|
||||
txExecutionState::init(Node* aNode,
|
||||
txExecutionState::init(const txXPathNode& aNode,
|
||||
txExpandedNameMap* aGlobalParams)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
@ -178,16 +166,15 @@ txExecutionState::init(Node* aNode,
|
|||
mOutputHandler->startDocument();
|
||||
|
||||
// Set up loaded-documents-hash
|
||||
Document* sourceDoc;
|
||||
if (aNode->getNodeType() == Node::DOCUMENT_NODE) {
|
||||
sourceDoc = (Document*)aNode;
|
||||
}
|
||||
else {
|
||||
sourceDoc = aNode->getOwnerDocument();
|
||||
}
|
||||
rv = mLoadedDocuments.init(sourceDoc);
|
||||
nsAutoPtr<txXPathNode> document(txXPathNodeUtils::getOwnerDocument(aNode));
|
||||
NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
|
||||
|
||||
rv = mLoadedDocuments.init(document);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// loaded-documents-hash owns this now
|
||||
document.forget();
|
||||
|
||||
// Init members
|
||||
rv = mKeyHash.init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -338,7 +325,7 @@ txExecutionState::getVariable(PRInt32 aNamespace, nsIAtom* aLName,
|
|||
}
|
||||
|
||||
PRBool
|
||||
txExecutionState::isStripSpaceAllowed(Node* aNode)
|
||||
txExecutionState::isStripSpaceAllowed(const txXPathNode& aNode)
|
||||
{
|
||||
return mStylesheet->isStripSpaceAllowed(aNode, this);
|
||||
}
|
||||
|
@ -474,70 +461,47 @@ txExecutionState::getEvalContext()
|
|||
return mEvalContext;
|
||||
}
|
||||
|
||||
Node*
|
||||
txExecutionState::retrieveDocument(const nsAString& uri,
|
||||
const nsAString& baseUri)
|
||||
const txXPathNode*
|
||||
txExecutionState::retrieveDocument(const nsAString& aUri)
|
||||
{
|
||||
nsAutoString absUrl;
|
||||
URIUtils::resolveHref(uri, baseUri, absUrl);
|
||||
|
||||
PRInt32 hash = absUrl.RFindChar(PRUnichar('#'));
|
||||
PRUint32 urlEnd, fragStart, fragEnd;
|
||||
if (hash == kNotFound) {
|
||||
urlEnd = absUrl.Length();
|
||||
fragStart = 0;
|
||||
fragEnd = 0;
|
||||
}
|
||||
else {
|
||||
urlEnd = hash;
|
||||
fragStart = hash + 1;
|
||||
fragEnd = absUrl.Length();
|
||||
}
|
||||
|
||||
nsDependentSubstring docUrl(absUrl, 0, urlEnd);
|
||||
nsDependentSubstring frag(absUrl, fragStart, fragEnd);
|
||||
NS_ASSERTION(aUri.FindChar(PRUnichar('#')) == kNotFound,
|
||||
"Remove the fragment.");
|
||||
|
||||
PR_LOG(txLog::xslt, PR_LOG_DEBUG,
|
||||
("Retrieve Document %s, uri %s, baseUri %s, fragment %s\n",
|
||||
NS_LossyConvertUCS2toASCII(docUrl).get(),
|
||||
NS_LossyConvertUCS2toASCII(uri).get(),
|
||||
NS_LossyConvertUCS2toASCII(baseUri).get(),
|
||||
NS_LossyConvertUCS2toASCII(frag).get()));
|
||||
("Retrieve Document %s", NS_LossyConvertUCS2toASCII(aUri).get()));
|
||||
|
||||
// try to get already loaded document
|
||||
Document* xmlDoc = mLoadedDocuments.Get(docUrl);
|
||||
txLoadedDocumentEntry *entry = mLoadedDocuments.PutEntry(aUri);
|
||||
if (!entry) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
if (!xmlDoc) {
|
||||
if (!entry->mDocument) {
|
||||
// open URI
|
||||
nsAutoString errMsg, refUri;
|
||||
// XXX we should get the referrer from the actual node
|
||||
// triggering the load, but this will do for the time being
|
||||
mLoadedDocuments.mSourceDocument->getBaseURI(refUri);
|
||||
txXPathNodeUtils::getBaseURI(*mLoadedDocuments.mSourceDocument, refUri);
|
||||
nsresult rv;
|
||||
rv = txParseDocumentFromURI(docUrl, refUri,
|
||||
mLoadedDocuments.mSourceDocument, errMsg,
|
||||
&xmlDoc);
|
||||
rv = txParseDocumentFromURI(aUri, refUri,
|
||||
*mLoadedDocuments.mSourceDocument, errMsg,
|
||||
getter_Transfers(entry->mDocument));
|
||||
|
||||
if (NS_FAILED(rv) || !xmlDoc) {
|
||||
if (NS_FAILED(rv) || !entry->mDocument) {
|
||||
mLoadedDocuments.RawRemoveEntry(entry);
|
||||
receiveError(NS_LITERAL_STRING("Couldn't load document '") +
|
||||
docUrl + NS_LITERAL_STRING("': ") + errMsg, rv);
|
||||
aUri + NS_LITERAL_STRING("': ") + errMsg, rv);
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
// add to list of documents
|
||||
mLoadedDocuments.Add(xmlDoc);
|
||||
}
|
||||
|
||||
// return element with supplied id if supplied
|
||||
if (!frag.IsEmpty()) {
|
||||
return xmlDoc->getElementById(frag);
|
||||
}
|
||||
|
||||
return xmlDoc;
|
||||
return entry->mDocument;
|
||||
}
|
||||
|
||||
nsresult
|
||||
txExecutionState::getKeyNodes(const txExpandedName& aKeyName,
|
||||
Document* aDocument,
|
||||
const txXPathNode& aDocument,
|
||||
const nsAString& aKeyValue,
|
||||
PRBool aIndexIfNotFound,
|
||||
txNodeSet** aResult)
|
||||
|
|
|
@ -47,7 +47,8 @@
|
|||
#include "nsVoidArray.h"
|
||||
#include "txIXPathContext.h"
|
||||
#include "txVariableMap.h"
|
||||
#include "nsDoubleHashtable.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "txKey.h"
|
||||
#include "txStylesheet.h"
|
||||
|
||||
|
@ -55,32 +56,36 @@ class txInstruction;
|
|||
class txIOutputHandlerFactory;
|
||||
class txExpandedNameMap;
|
||||
|
||||
class txLoadedDocumentEntry : public PLDHashStringEntry
|
||||
class txLoadedDocumentEntry : public nsStringHashKey
|
||||
{
|
||||
public:
|
||||
txLoadedDocumentEntry(const void* aKey) : PLDHashStringEntry(aKey)
|
||||
txLoadedDocumentEntry(KeyTypePointer aStr) : nsStringHashKey(aStr)
|
||||
{
|
||||
}
|
||||
txLoadedDocumentEntry(const txLoadedDocumentEntry& aToCopy)
|
||||
: nsStringHashKey(aToCopy)
|
||||
{
|
||||
NS_ERROR("We're horked.");
|
||||
}
|
||||
~txLoadedDocumentEntry()
|
||||
{
|
||||
delete mDocument;
|
||||
if (mDocument) {
|
||||
txXPathNodeUtils::release(mDocument);
|
||||
}
|
||||
}
|
||||
Document* mDocument;
|
||||
|
||||
nsAutoPtr<txXPathNode> mDocument;
|
||||
};
|
||||
|
||||
DECL_DHASH_WRAPPER(txLoadedDocumentsBase, txLoadedDocumentEntry, nsAString&)
|
||||
|
||||
class txLoadedDocumentsHash : public txLoadedDocumentsBase
|
||||
class txLoadedDocumentsHash : public nsTHashtable<txLoadedDocumentEntry>
|
||||
{
|
||||
public:
|
||||
~txLoadedDocumentsHash();
|
||||
nsresult init(Document* aSourceDocument);
|
||||
void Add(Document* aDocument);
|
||||
Document* Get(const nsAString& aURI);
|
||||
nsresult init(txXPathNode* aSourceDocument);
|
||||
|
||||
private:
|
||||
friend class txExecutionState;
|
||||
Document* mSourceDocument;
|
||||
txXPathNode* mSourceDocument;
|
||||
};
|
||||
|
||||
|
||||
|
@ -89,7 +94,7 @@ class txExecutionState : public txIMatchContext
|
|||
public:
|
||||
txExecutionState(txStylesheet* aStylesheet);
|
||||
~txExecutionState();
|
||||
nsresult init(Node* aNode, txExpandedNameMap* aGlobalParams);
|
||||
nsresult init(const txXPathNode& aNode, txExpandedNameMap* aGlobalParams);
|
||||
nsresult end();
|
||||
|
||||
TX_DECL_MATCH_CONTEXT;
|
||||
|
@ -123,8 +128,9 @@ public:
|
|||
// state-getting functions
|
||||
txIEvalContext* getEvalContext();
|
||||
txExpandedNameMap* getParamMap();
|
||||
Node* retrieveDocument(const nsAString& uri, const nsAString& baseUri);
|
||||
nsresult getKeyNodes(const txExpandedName& aKeyName, Document* aDocument,
|
||||
const txXPathNode* retrieveDocument(const nsAString& aUri);
|
||||
nsresult getKeyNodes(const txExpandedName& aKeyName,
|
||||
const txXPathNode& aDocument,
|
||||
const nsAString& aKeyValue, PRBool aIndexIfNotFound,
|
||||
txNodeSet** aResult);
|
||||
TemplateRule* getCurrentTemplateRule();
|
||||
|
@ -168,7 +174,7 @@ private:
|
|||
|
||||
txIEvalContext* mEvalContext;
|
||||
txIEvalContext* mInitialEvalContext;
|
||||
Document* mRTFDocument;
|
||||
//Document* mRTFDocument;
|
||||
txExpandedNameMap* mGlobalParams;
|
||||
|
||||
txLoadedDocumentsHash mLoadedDocuments;
|
||||
|
|
|
@ -22,22 +22,16 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "ExprResult.h"
|
||||
#include "txAtoms.h"
|
||||
#include "txIXPathContext.h"
|
||||
#include "XSLTFunctions.h"
|
||||
#include "prprf.h"
|
||||
#include "txNodeSet.h"
|
||||
#include "XSLTFunctions.h"
|
||||
|
||||
/*
|
||||
Implementation of XSLT 1.0 extension function: generate-id
|
||||
*/
|
||||
|
||||
#ifndef HAVE_64BIT_OS
|
||||
const char GenerateIdFunctionCall::printfFmt[] = "id0x%08p";
|
||||
#else
|
||||
const char GenerateIdFunctionCall::printfFmt[] = "id0x%016p";
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates a new generate-id function call
|
||||
**/
|
||||
|
@ -61,43 +55,41 @@ GenerateIdFunctionCall::evaluate(txIEvalContext* aContext,
|
|||
if (!requireParams(0, 1, aContext))
|
||||
return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
|
||||
|
||||
Node* node = 0;
|
||||
|
||||
// get node to generate id for
|
||||
if (params.getLength() == 1) {
|
||||
txListIterator iter(¶ms);
|
||||
Expr* param = (Expr*)iter.next();
|
||||
|
||||
nsRefPtr<txAExprResult> exprResult;
|
||||
nsresult rv = param->evaluate(aContext, getter_AddRefs(exprResult));
|
||||
nsresult rv = NS_OK;
|
||||
if (params.getLength() != 1) {
|
||||
StringResult* strRes;
|
||||
rv = aContext->recycler()->getStringResult(&strRes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (exprResult->getResultType() != txAExprResult::NODESET) {
|
||||
NS_NAMED_LITERAL_STRING(err, "Invalid argument passed to generate-id(), expecting NodeSet");
|
||||
aContext->receiveError(err, NS_ERROR_XSLT_NODESET_EXPECTED);
|
||||
return NS_ERROR_XSLT_NODESET_EXPECTED;
|
||||
}
|
||||
txXPathNodeUtils::getXSLTId(aContext->getContextNode(),
|
||||
strRes->mValue);
|
||||
|
||||
txNodeSet* nodes = NS_STATIC_CAST(txNodeSet*,
|
||||
NS_STATIC_CAST(txAExprResult*,
|
||||
exprResult));
|
||||
if (nodes->isEmpty()) {
|
||||
aContext->recycler()->getEmptyStringResult(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
node = nodes->get(0);
|
||||
}
|
||||
else {
|
||||
node = aContext->getContextNode();
|
||||
*aResult = strRes;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// generate id for selected node
|
||||
char buf[22];
|
||||
PR_snprintf(buf, 21, printfFmt, node);
|
||||
return aContext->recycler()->getStringResult(NS_ConvertASCIItoUCS2(buf),
|
||||
aResult);
|
||||
txListIterator iter(¶ms);
|
||||
nsRefPtr<txNodeSet> nodes;
|
||||
rv = evaluateToNodeSet(NS_STATIC_CAST(Expr*, iter.next()), aContext,
|
||||
getter_AddRefs(nodes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (nodes->isEmpty()) {
|
||||
aContext->recycler()->getEmptyStringResult(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
StringResult* strRes;
|
||||
rv = aContext->recycler()->getStringResult(&strRes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
txXPathNodeUtils::getXSLTId(nodes->get(0), strRes->mValue);
|
||||
|
||||
*aResult = strRes;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult GenerateIdFunctionCall::getNameAtom(nsIAtom** aAtom)
|
||||
|
|
|
@ -278,84 +278,82 @@ txComment::execute(txExecutionState& aEs)
|
|||
}
|
||||
|
||||
nsresult
|
||||
txCopyBase::copyNode(Node* aNode, txExecutionState& aEs)
|
||||
txCopyBase::copyNode(const txXPathNode& aNode, txExecutionState& aEs)
|
||||
{
|
||||
NS_ASSERTION(aNode, "missing node to copy");
|
||||
switch (aNode->getNodeType()) {
|
||||
case Node::ATTRIBUTE_NODE:
|
||||
switch (txXPathNodeUtils::getNodeType(aNode)) {
|
||||
case txXPathNodeType::ATTRIBUTE_NODE:
|
||||
{
|
||||
nsAutoString nodeName, nodeValue;
|
||||
aNode->getNodeName(nodeName);
|
||||
aNode->getNodeValue(nodeValue);
|
||||
txXPathNodeUtils::getNodeName(aNode, nodeName);
|
||||
txXPathNodeUtils::appendNodeValue(aNode, nodeValue);
|
||||
aEs.mResultHandler->attribute(nodeName,
|
||||
aNode->getNamespaceID(),
|
||||
txXPathNodeUtils::getNamespaceID(aNode),
|
||||
nodeValue);
|
||||
break;
|
||||
}
|
||||
case Node::COMMENT_NODE:
|
||||
case txXPathNodeType::COMMENT_NODE:
|
||||
{
|
||||
nsAutoString nodeValue;
|
||||
aNode->getNodeValue(nodeValue);
|
||||
txXPathNodeUtils::appendNodeValue(aNode, nodeValue);
|
||||
aEs.mResultHandler->comment(nodeValue);
|
||||
break;
|
||||
}
|
||||
case Node::DOCUMENT_NODE:
|
||||
case Node::DOCUMENT_FRAGMENT_NODE:
|
||||
case txXPathNodeType::DOCUMENT_NODE:
|
||||
case txXPathNodeType::DOCUMENT_FRAGMENT_NODE:
|
||||
{
|
||||
// Copy children
|
||||
Node* child = aNode->getFirstChild();
|
||||
while (child) {
|
||||
copyNode(child, aEs);
|
||||
child = child->getNextSibling();
|
||||
txXPathTreeWalker walker(aNode);
|
||||
PRBool hasChild = walker.moveToFirstChild();
|
||||
while (hasChild) {
|
||||
copyNode(walker.getCurrentPosition(), aEs);
|
||||
hasChild = walker.moveToNextSibling();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Node::ELEMENT_NODE:
|
||||
case txXPathNodeType::ELEMENT_NODE:
|
||||
{
|
||||
Element* element = NS_STATIC_CAST(Element*, aNode);
|
||||
nsAutoString name;
|
||||
element->getNodeName(name);
|
||||
PRInt32 nsID = element->getNamespaceID();
|
||||
txXPathNodeUtils::getNodeName(aNode, name);
|
||||
PRInt32 nsID = txXPathNodeUtils::getNamespaceID(aNode);
|
||||
aEs.mResultHandler->startElement(name, nsID);
|
||||
|
||||
// Copy attributes
|
||||
NamedNodeMap* attList = element->getAttributes();
|
||||
if (attList) {
|
||||
PRUint32 i = 0;
|
||||
for (i = 0; i < attList->getLength(); i++) {
|
||||
Attr* attr = NS_STATIC_CAST(Attr*, attList->item(i));
|
||||
txXPathTreeWalker walker(aNode);
|
||||
if (walker.moveToFirstAttribute()) {
|
||||
do {
|
||||
nsAutoString nodeName, nodeValue;
|
||||
attr->getNodeName(nodeName);
|
||||
attr->getNodeValue(nodeValue);
|
||||
walker.getNodeName(nodeName);
|
||||
walker.appendNodeValue(nodeValue);
|
||||
aEs.mResultHandler->attribute(nodeName,
|
||||
attr->getNamespaceID(),
|
||||
walker.getNamespaceID(),
|
||||
nodeValue);
|
||||
}
|
||||
} while (walker.moveToNextAttribute());
|
||||
walker.moveToParent();
|
||||
}
|
||||
|
||||
// Copy children
|
||||
Node* child = element->getFirstChild();
|
||||
while (child) {
|
||||
copyNode(child, aEs);
|
||||
child = child->getNextSibling();
|
||||
PRBool hasChild = walker.moveToFirstChild();
|
||||
while (hasChild) {
|
||||
copyNode(walker.getCurrentPosition(), aEs);
|
||||
hasChild = walker.moveToNextSibling();
|
||||
}
|
||||
|
||||
aEs.mResultHandler->endElement(name, nsID);
|
||||
break;
|
||||
}
|
||||
case Node::PROCESSING_INSTRUCTION_NODE:
|
||||
case txXPathNodeType::PROCESSING_INSTRUCTION_NODE:
|
||||
{
|
||||
nsAutoString target, data;
|
||||
aNode->getNodeName(target);
|
||||
aNode->getNodeValue(data);
|
||||
txXPathNodeUtils::getNodeName(aNode, target);
|
||||
txXPathNodeUtils::appendNodeValue(aNode, data);
|
||||
aEs.mResultHandler->processingInstruction(target, data);
|
||||
break;
|
||||
}
|
||||
case Node::TEXT_NODE:
|
||||
case Node::CDATA_SECTION_NODE:
|
||||
case txXPathNodeType::TEXT_NODE:
|
||||
case txXPathNodeType::CDATA_SECTION_NODE:
|
||||
{
|
||||
nsAutoString nodeValue;
|
||||
aNode->getNodeValue(nodeValue);
|
||||
txXPathNodeUtils::appendNodeValue(aNode, nodeValue);
|
||||
aEs.mResultHandler->characters(nodeValue, PR_FALSE);
|
||||
break;
|
||||
}
|
||||
|
@ -373,10 +371,10 @@ nsresult
|
|||
txCopy::execute(txExecutionState& aEs)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
Node* node = aEs.getEvalContext()->getContextNode();
|
||||
const txXPathNode& node = aEs.getEvalContext()->getContextNode();
|
||||
|
||||
switch (node->getNodeType()) {
|
||||
case Node::DOCUMENT_NODE:
|
||||
switch (txXPathNodeUtils::getNodeType(node)) {
|
||||
case txXPathNodeType::DOCUMENT_NODE:
|
||||
{
|
||||
// "close" current element to ensure that no attributes are added
|
||||
aEs.mResultHandler->characters(NS_LITERAL_STRING(""), PR_FALSE);
|
||||
|
@ -389,11 +387,11 @@ txCopy::execute(txExecutionState& aEs)
|
|||
|
||||
break;
|
||||
}
|
||||
case Node::ELEMENT_NODE:
|
||||
case txXPathNodeType::ELEMENT_NODE:
|
||||
{
|
||||
nsAutoString nodeName;
|
||||
node->getNodeName(nodeName);
|
||||
PRInt32 nsID = node->getNamespaceID();
|
||||
txXPathNodeUtils::getNodeName(node, nodeName);
|
||||
PRInt32 nsID = txXPathNodeUtils::getNamespaceID(node);
|
||||
|
||||
aEs.mResultHandler->startElement(nodeName, nsID);
|
||||
// XXX copy namespace nodes once we have them
|
||||
|
|
|
@ -154,7 +154,7 @@ public:
|
|||
class txCopyBase : public txInstruction
|
||||
{
|
||||
protected:
|
||||
nsresult copyNode(Node* aNode, txExecutionState& aEs);
|
||||
nsresult copyNode(const txXPathNode& aNode, txExecutionState& aEs);
|
||||
};
|
||||
|
||||
class txCopy : public txCopyBase
|
||||
|
|
|
@ -53,17 +53,17 @@ class txKeyValueHashKey
|
|||
{
|
||||
public:
|
||||
txKeyValueHashKey(const txExpandedName& aKeyName,
|
||||
Document* aDocument,
|
||||
PRInt32 aDocumentIdentifier,
|
||||
const nsAString& aKeyValue)
|
||||
: mKeyName(aKeyName),
|
||||
mKeyValue(aKeyValue),
|
||||
mDocument(aDocument)
|
||||
mDocumentIdentifier(aDocumentIdentifier)
|
||||
{
|
||||
}
|
||||
|
||||
txExpandedName mKeyName;
|
||||
nsString mKeyValue;
|
||||
Document* mDocument;
|
||||
PRInt32 mDocumentIdentifier;
|
||||
};
|
||||
|
||||
struct txKeyValueHashEntry : public PLDHashEntryHdr
|
||||
|
@ -89,14 +89,14 @@ class txIndexedKeyHashKey
|
|||
{
|
||||
public:
|
||||
txIndexedKeyHashKey(txExpandedName aKeyName,
|
||||
Document* aDocument)
|
||||
PRInt32 aDocumentIdentifier)
|
||||
: mKeyName(aKeyName),
|
||||
mDocument(aDocument)
|
||||
mDocumentIdentifier(aDocumentIdentifier)
|
||||
{
|
||||
}
|
||||
|
||||
txExpandedName mKeyName;
|
||||
Document* mDocument;
|
||||
PRInt32 mDocumentIdentifier;
|
||||
};
|
||||
|
||||
struct txIndexedKeyHashEntry : public PLDHashEntryHdr
|
||||
|
@ -145,7 +145,7 @@ public:
|
|||
* @param aKeyValueHash Hash to add values to
|
||||
* @param aEs txExecutionState to use for XPath evaluation
|
||||
*/
|
||||
nsresult indexDocument(Document* aDocument,
|
||||
nsresult indexDocument(const txXPathNode& aDocument,
|
||||
txKeyValueHash& aKeyValueHash,
|
||||
txExecutionState& aEs);
|
||||
|
||||
|
@ -158,7 +158,7 @@ private:
|
|||
* @param aKeyValueHash Hash to add values to
|
||||
* @param aEs txExecutionState to use for XPath evaluation
|
||||
*/
|
||||
nsresult indexTree(Node* aNode, txKeyValueHashKey& aKey,
|
||||
nsresult indexTree(const txXPathNode& aNode, txKeyValueHashKey& aKey,
|
||||
txKeyValueHash& aKeyValueHash, txExecutionState& aEs);
|
||||
|
||||
/**
|
||||
|
@ -169,7 +169,7 @@ private:
|
|||
* @param aKeyValueHash Hash to add values to
|
||||
* @param aEs txExecutionState to use for XPath evaluation
|
||||
*/
|
||||
nsresult testNode(Node* aNode, txKeyValueHashKey& aKey,
|
||||
nsresult testNode(const txXPathNode& aNode, txKeyValueHashKey& aKey,
|
||||
txKeyValueHash& aKeyValueHash, txExecutionState& aEs);
|
||||
|
||||
/**
|
||||
|
@ -203,7 +203,7 @@ public:
|
|||
nsresult init();
|
||||
|
||||
nsresult getKeyNodes(const txExpandedName& aKeyName,
|
||||
Document* aDocument,
|
||||
const txXPathNode& aDocument,
|
||||
const nsAString& aKeyValue,
|
||||
PRBool aIndexIfNotFound,
|
||||
txExecutionState& aEs,
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "txExecutionState.h"
|
||||
#include "txAtoms.h"
|
||||
#include "txSingleNodeContext.h"
|
||||
#include "XMLDOMUtils.h"
|
||||
#include "XSLTFunctions.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "txKey.h"
|
||||
|
@ -70,12 +69,8 @@ txKeyFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
rv = ((Expr*)iter.next())->evaluate(aContext, getter_AddRefs(exprResult));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
Document* contextDoc;
|
||||
Node* contextNode = aContext->getContextNode();
|
||||
if (contextNode->getNodeType() == Node::DOCUMENT_NODE)
|
||||
contextDoc = (Document*)contextNode;
|
||||
else
|
||||
contextDoc = contextNode->getOwnerDocument();
|
||||
nsAutoPtr<txXPathNode> contextDoc(txXPathNodeUtils::getOwnerDocument(aContext->getContextNode()));
|
||||
NS_ENSURE_TRUE(contextDoc, NS_ERROR_FAILURE);
|
||||
|
||||
nsRefPtr<txNodeSet> res;
|
||||
txNodeSet* nodeSet;
|
||||
|
@ -89,20 +84,20 @@ txKeyFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
PRInt32 i;
|
||||
for (i = 0; i < nodeSet->size(); ++i) {
|
||||
nsAutoString val;
|
||||
XMLDOMUtils::getNodeValue(nodeSet->get(i), val);
|
||||
txXPathNodeUtils::appendNodeValue(nodeSet->get(i), val);
|
||||
|
||||
nsRefPtr<txNodeSet> nodes;
|
||||
rv = es->getKeyNodes(keyName, contextDoc, val, i == 0,
|
||||
rv = es->getKeyNodes(keyName, *contextDoc, val, i == 0,
|
||||
getter_AddRefs(nodes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
res->add(nodes);
|
||||
res->add(*nodes);
|
||||
}
|
||||
}
|
||||
else {
|
||||
nsAutoString val;
|
||||
exprResult->stringValue(val);
|
||||
rv = es->getKeyNodes(keyName, contextDoc, val, PR_TRUE,
|
||||
rv = es->getKeyNodes(keyName, *contextDoc, val, PR_TRUE,
|
||||
getter_AddRefs(res));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
@ -140,7 +135,7 @@ txKeyValueHashEntry::MatchEntry(const void* aKey) const
|
|||
NS_STATIC_CAST(const txKeyValueHashKey*, aKey);
|
||||
|
||||
return mKey.mKeyName == key->mKeyName &&
|
||||
mKey.mDocument == key->mDocument &&
|
||||
mKey.mDocumentIdentifier == key->mDocumentIdentifier &&
|
||||
mKey.mKeyValue.Equals(key->mKeyValue);
|
||||
}
|
||||
|
||||
|
@ -152,7 +147,7 @@ txKeyValueHashEntry::HashKey(const void* aKey)
|
|||
|
||||
return key->mKeyName.mNamespaceID ^
|
||||
NS_PTR_TO_INT32(key->mKeyName.mLocalName.get()) ^
|
||||
NS_PTR_TO_INT32(key->mDocument) ^
|
||||
key->mDocumentIdentifier ^
|
||||
HashString(key->mKeyValue);
|
||||
}
|
||||
|
||||
|
@ -169,7 +164,7 @@ txIndexedKeyHashEntry::MatchEntry(const void* aKey) const
|
|||
NS_STATIC_CAST(const txIndexedKeyHashKey*, aKey);
|
||||
|
||||
return mKey.mKeyName == key->mKeyName &&
|
||||
mKey.mDocument == key->mDocument;
|
||||
mKey.mDocumentIdentifier == key->mDocumentIdentifier;
|
||||
}
|
||||
|
||||
PLDHashNumber
|
||||
|
@ -180,7 +175,7 @@ txIndexedKeyHashEntry::HashKey(const void* aKey)
|
|||
|
||||
return key->mKeyName.mNamespaceID ^
|
||||
NS_PTR_TO_INT32(key->mKeyName.mLocalName.get()) ^
|
||||
NS_PTR_TO_INT32(key->mDocument);
|
||||
key->mDocumentIdentifier;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -189,7 +184,7 @@ txIndexedKeyHashEntry::HashKey(const void* aKey)
|
|||
|
||||
nsresult
|
||||
txKeyHash::getKeyNodes(const txExpandedName& aKeyName,
|
||||
Document* aDocument,
|
||||
const txXPathNode& aDocument,
|
||||
const nsAString& aKeyValue,
|
||||
PRBool aIndexIfNotFound,
|
||||
txExecutionState& aEs,
|
||||
|
@ -199,7 +194,10 @@ txKeyHash::getKeyNodes(const txExpandedName& aKeyName,
|
|||
NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
*aResult = nsnull;
|
||||
txKeyValueHashKey valueKey(aKeyName, aDocument, aKeyValue);
|
||||
|
||||
PRInt32 identifier = txXPathNodeUtils::getUniqueIdentifier(aDocument);
|
||||
|
||||
txKeyValueHashKey valueKey(aKeyName, identifier, aKeyValue);
|
||||
txKeyValueHashEntry* valueEntry = mKeyValues.GetEntry(valueKey);
|
||||
if (valueEntry) {
|
||||
*aResult = valueEntry->mNodeSet;
|
||||
|
@ -221,7 +219,7 @@ txKeyHash::getKeyNodes(const txExpandedName& aKeyName,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
txIndexedKeyHashKey indexKey(aKeyName, aDocument);
|
||||
txIndexedKeyHashKey indexKey(aKeyName, identifier);
|
||||
txIndexedKeyHashEntry* indexEntry = mIndexedKeys.AddEntry(indexKey);
|
||||
NS_ENSURE_TRUE(indexEntry, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
|
@ -230,6 +228,7 @@ txKeyHash::getKeyNodes(const txExpandedName& aKeyName,
|
|||
// return the empty nodeset.
|
||||
*aResult = mEmptyNodeSet;
|
||||
NS_ADDREF(*aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -318,11 +317,13 @@ PRBool txXSLKey::addKey(nsAutoPtr<txPattern> aMatch, nsAutoPtr<Expr> aUse)
|
|||
* @param aKeyValueHash Hash to add values to
|
||||
* @param aEs txExecutionState to use for XPath evaluation
|
||||
*/
|
||||
nsresult txXSLKey::indexDocument(Document* aDocument,
|
||||
nsresult txXSLKey::indexDocument(const txXPathNode& aDocument,
|
||||
txKeyValueHash& aKeyValueHash,
|
||||
txExecutionState& aEs)
|
||||
{
|
||||
txKeyValueHashKey key(mName, aDocument, NS_LITERAL_STRING(""));
|
||||
txKeyValueHashKey key(mName,
|
||||
txXPathNodeUtils::getUniqueIdentifier(aDocument),
|
||||
NS_LITERAL_STRING(""));
|
||||
return indexTree(aDocument, key, aKeyValueHash, aEs);
|
||||
}
|
||||
|
||||
|
@ -334,30 +335,34 @@ nsresult txXSLKey::indexDocument(Document* aDocument,
|
|||
* @param aKeyValueHash Hash to add values to
|
||||
* @param aEs txExecutionState to use for XPath evaluation
|
||||
*/
|
||||
nsresult txXSLKey::indexTree(Node* aNode, txKeyValueHashKey& aKey,
|
||||
nsresult txXSLKey::indexTree(const txXPathNode& aNode,
|
||||
txKeyValueHashKey& aKey,
|
||||
txKeyValueHash& aKeyValueHash,
|
||||
txExecutionState& aEs)
|
||||
{
|
||||
nsresult rv = testNode(aNode, aKey, aKeyValueHash, aEs);
|
||||
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++) {
|
||||
rv = testNode(attrs->item(i), aKey, aKeyValueHash, aEs);
|
||||
// check if the node's attributes match
|
||||
txXPathTreeWalker walker(aNode);
|
||||
if (walker.moveToFirstAttribute()) {
|
||||
do {
|
||||
rv = testNode(walker.getCurrentPosition(), aKey, aKeyValueHash,
|
||||
aEs);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
} while (walker.moveToNextAttribute());
|
||||
walker.moveToParent();
|
||||
}
|
||||
|
||||
Node* child = aNode->getFirstChild();
|
||||
while (child) {
|
||||
rv = indexTree(child, aKey, aKeyValueHash, aEs);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
child = child->getNextSibling();
|
||||
// check if the node's descendants match
|
||||
if (walker.moveToFirstChild()) {
|
||||
do {
|
||||
rv = indexTree(walker.getCurrentPosition(), aKey, aKeyValueHash,
|
||||
aEs);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} while (walker.moveToNextSibling());
|
||||
}
|
||||
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -369,7 +374,7 @@ nsresult txXSLKey::indexTree(Node* aNode, txKeyValueHashKey& aKey,
|
|||
* @param aKeyValueHash Hash to add values to
|
||||
* @param aEs txExecutionState to use for XPath evaluation
|
||||
*/
|
||||
nsresult txXSLKey::testNode(Node* aNode,
|
||||
nsresult txXSLKey::testNode(const txXPathNode& aNode,
|
||||
txKeyValueHashKey& aKey,
|
||||
txKeyValueHash& aKeyValueHash,
|
||||
txExecutionState& aEs)
|
||||
|
@ -398,7 +403,7 @@ nsresult txXSLKey::testNode(Node* aNode,
|
|||
PRInt32 i;
|
||||
for (i = 0; i < res->size(); ++i) {
|
||||
val.Truncate();
|
||||
XMLDOMUtils::getNodeValue(res->get(i), val);
|
||||
txXPathNodeUtils::appendNodeValue(res->get(i), val);
|
||||
|
||||
aKey.mKeyValue.Assign(val);
|
||||
txKeyValueHashEntry* entry = aKeyValueHash.AddEntry(aKey);
|
||||
|
|
|
@ -630,7 +630,7 @@ handleNode(nsIDOMNode* aNode, txStylesheetCompiler* aCompiler)
|
|||
{
|
||||
nsCOMPtr<nsIDocument> document = do_QueryInterface(aNode);
|
||||
|
||||
PRInt32 counter = 0;
|
||||
PRUint32 counter = 0;
|
||||
nsIContent *child;
|
||||
while ((child = document->GetChildAt(counter++))) {
|
||||
nsCOMPtr<nsIDOMNode> childNode = do_QueryInterface(child);
|
||||
|
|
|
@ -57,7 +57,6 @@
|
|||
#include "txExecutionState.h"
|
||||
#include "txMozillaTextOutput.h"
|
||||
#include "txMozillaXMLOutput.h"
|
||||
#include "txSingleNodeContext.h"
|
||||
#include "txURIUtils.h"
|
||||
#include "XMLUtils.h"
|
||||
#include "txUnknownHandler.h"
|
||||
|
@ -290,24 +289,27 @@ txMozillaXSLTProcessor::TransformDocument(nsIDOMNode* aSourceDOM,
|
|||
|
||||
nsresult rv = TX_CompileStylesheet(aStyleDOM, getter_AddRefs(mStylesheet));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// Create wrapper for the source document.
|
||||
|
||||
mSource = aSourceDOM;
|
||||
nsCOMPtr<nsIDOMDocument> sourceDOMDocument;
|
||||
mSource->GetOwnerDocument(getter_AddRefs(sourceDOMDocument));
|
||||
if (!sourceDOMDocument) {
|
||||
sourceDOMDocument = do_QueryInterface(mSource);
|
||||
|
||||
nsAutoPtr<txXPathNode> sourceNode(txXPathNativeNode::createXPathNode(aSourceDOM));
|
||||
if (!sourceNode) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> sourceDOMDocument;
|
||||
aSourceDOM->GetOwnerDocument(getter_AddRefs(sourceDOMDocument));
|
||||
if (!sourceDOMDocument) {
|
||||
sourceDOMDocument = do_QueryInterface(aSourceDOM);
|
||||
}
|
||||
NS_ENSURE_TRUE(sourceDOMDocument, NS_ERROR_FAILURE);
|
||||
Document sourceDocument(sourceDOMDocument);
|
||||
Node* sourceNode = sourceDocument.createWrapper(mSource);
|
||||
NS_ENSURE_TRUE(sourceNode, NS_ERROR_FAILURE);
|
||||
|
||||
txExecutionState es(mStylesheet);
|
||||
|
||||
txToDocHandlerFactory handlerFactory(&es, sourceDOMDocument, aOutputDoc,
|
||||
nsnull);
|
||||
es.mOutputHandlerFactory = &handlerFactory;
|
||||
|
||||
es.init(sourceNode, &mVariables);
|
||||
es.init(*sourceNode, &mVariables);
|
||||
|
||||
// Process root of XML source document
|
||||
rv = txXSLTProcessor::execute(es);
|
||||
|
@ -348,16 +350,16 @@ txMozillaXSLTProcessor::DoTransform()
|
|||
NS_ENSURE_TRUE(mStylesheet, NS_ERROR_UNEXPECTED);
|
||||
NS_ASSERTION(mObserver, "no observer");
|
||||
|
||||
// Create wrapper for the source document.
|
||||
nsAutoPtr<txXPathNode> sourceNode(txXPathNativeNode::createXPathNode(mSource));
|
||||
if (!sourceNode) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> sourceDOMDocument;
|
||||
mSource->GetOwnerDocument(getter_AddRefs(sourceDOMDocument));
|
||||
if (!sourceDOMDocument) {
|
||||
sourceDOMDocument = do_QueryInterface(mSource);
|
||||
}
|
||||
NS_ENSURE_TRUE(sourceDOMDocument, NS_ERROR_FAILURE);
|
||||
Document sourceDocument(sourceDOMDocument);
|
||||
Node* sourceNode = sourceDocument.createWrapper(mSource);
|
||||
NS_ENSURE_TRUE(sourceNode, NS_ERROR_FAILURE);
|
||||
|
||||
txExecutionState es(mStylesheet);
|
||||
|
||||
|
@ -367,7 +369,7 @@ txMozillaXSLTProcessor::DoTransform()
|
|||
mObserver);
|
||||
es.mOutputHandlerFactory = &handlerFactory;
|
||||
|
||||
es.init(sourceNode, &mVariables);
|
||||
es.init(*sourceNode, &mVariables);
|
||||
|
||||
// Process root of XML source document
|
||||
nsresult rv = txXSLTProcessor::execute(es);
|
||||
|
@ -437,16 +439,16 @@ txMozillaXSLTProcessor::TransformToDocument(nsIDOMNode *aSource,
|
|||
nsresult rv = ensureStylesheet();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Create wrapper for the source document.
|
||||
nsAutoPtr<txXPathNode> sourceNode(txXPathNativeNode::createXPathNode(aSource));
|
||||
if (!sourceNode) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> sourceDOMDocument;
|
||||
aSource->GetOwnerDocument(getter_AddRefs(sourceDOMDocument));
|
||||
if (!sourceDOMDocument) {
|
||||
sourceDOMDocument = do_QueryInterface(aSource);
|
||||
}
|
||||
NS_ENSURE_TRUE(sourceDOMDocument, NS_ERROR_FAILURE);
|
||||
Document sourceDocument(sourceDOMDocument);
|
||||
Node* sourceNode = sourceDocument.createWrapper(aSource);
|
||||
NS_ENSURE_TRUE(sourceNode, NS_ERROR_FAILURE);
|
||||
|
||||
txExecutionState es(mStylesheet);
|
||||
|
||||
|
@ -456,7 +458,7 @@ txMozillaXSLTProcessor::TransformToDocument(nsIDOMNode *aSource,
|
|||
nsnull);
|
||||
es.mOutputHandlerFactory = &handlerFactory;
|
||||
|
||||
es.init(sourceNode, &mVariables);
|
||||
es.init(*sourceNode, &mVariables);
|
||||
|
||||
// Process root of XML source document
|
||||
rv = txXSLTProcessor::execute(es);
|
||||
|
@ -490,16 +492,10 @@ txMozillaXSLTProcessor::TransformToFragment(nsIDOMNode *aSource,
|
|||
nsresult rv = ensureStylesheet();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Create wrapper for the source document.
|
||||
nsCOMPtr<nsIDOMDocument> sourceDOMDocument;
|
||||
aSource->GetOwnerDocument(getter_AddRefs(sourceDOMDocument));
|
||||
if (!sourceDOMDocument) {
|
||||
sourceDOMDocument = do_QueryInterface(aSource);
|
||||
nsAutoPtr<txXPathNode> sourceNode(txXPathNativeNode::createXPathNode(aSource));
|
||||
if (!sourceNode) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
NS_ENSURE_TRUE(sourceDOMDocument, NS_ERROR_FAILURE);
|
||||
Document sourceDocument(sourceDOMDocument);
|
||||
Node* sourceNode = sourceDocument.createWrapper(aSource);
|
||||
NS_ENSURE_TRUE(sourceNode, NS_ERROR_FAILURE);
|
||||
|
||||
txExecutionState es(mStylesheet);
|
||||
|
||||
|
@ -510,7 +506,7 @@ txMozillaXSLTProcessor::TransformToFragment(nsIDOMNode *aSource,
|
|||
txToFragmentHandlerFactory handlerFactory(*aResult);
|
||||
es.mOutputHandlerFactory = &handlerFactory;
|
||||
|
||||
es.init(sourceNode, &mVariables);
|
||||
es.init(*sourceNode, &mVariables);
|
||||
|
||||
// Process root of XML source document
|
||||
rv = txXSLTProcessor::execute(es);
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#include "ExprResult.h"
|
||||
#include "Expr.h"
|
||||
#include "txStringUtils.h"
|
||||
#include "txNodeSet.h"
|
||||
#include "prmem.h"
|
||||
#include "nsQuickSort.h"
|
||||
|
||||
|
|
|
@ -43,10 +43,10 @@
|
|||
#include "baseutils.h"
|
||||
#include "List.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "txXPathNode.h"
|
||||
|
||||
class Element;
|
||||
class Expr;
|
||||
class Node;
|
||||
class txExecutionState;
|
||||
class txNodeSet;
|
||||
class TxObject;
|
||||
|
|
|
@ -317,11 +317,11 @@ nsresult txPatternParser::createStepPattern(txExprLexer& aLexer,
|
|||
}
|
||||
if (isAttr) {
|
||||
nodeTest = new txNameTest(prefix, lName, nspace,
|
||||
Node::ATTRIBUTE_NODE);
|
||||
txXPathNodeType::ATTRIBUTE_NODE);
|
||||
}
|
||||
else {
|
||||
nodeTest = new txNameTest(prefix, lName, nspace,
|
||||
Node::ELEMENT_NODE);
|
||||
txXPathNodeType::ELEMENT_NODE);
|
||||
}
|
||||
if (!nodeTest) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
#include "nsCRT.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "txHTMLOutput.h"
|
||||
#include "txSingleNodeContext.h"
|
||||
#include "txTextOutput.h"
|
||||
#include "txUnknownHandler.h"
|
||||
#include "txURIUtils.h"
|
||||
|
@ -127,13 +126,13 @@ nsresult
|
|||
txStandaloneXSLTProcessor::transform(nsACString& aXMLPath, ostream& aOut,
|
||||
ErrorObserver& aErr)
|
||||
{
|
||||
Document* xmlDoc = parsePath(aXMLPath, aErr);
|
||||
txXPathNode* xmlDoc = parsePath(aXMLPath, aErr);
|
||||
if (!xmlDoc) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// transform
|
||||
nsresult rv = transform(xmlDoc, aOut, aErr);
|
||||
nsresult rv = transform(*xmlDoc, aOut, aErr);
|
||||
|
||||
delete xmlDoc;
|
||||
|
||||
|
@ -149,7 +148,7 @@ txStandaloneXSLTProcessor::transform(nsACString& aXMLPath,
|
|||
nsACString& aXSLPath, ostream& aOut,
|
||||
ErrorObserver& aErr)
|
||||
{
|
||||
Document* xmlDoc = parsePath(aXMLPath, aErr);
|
||||
txXPathNode* xmlDoc = parsePath(aXMLPath, aErr);
|
||||
if (!xmlDoc) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -162,7 +161,7 @@ txStandaloneXSLTProcessor::transform(nsACString& aXMLPath,
|
|||
return rv;
|
||||
}
|
||||
// transform
|
||||
rv = transform(xmlDoc, style, aOut, aErr);
|
||||
rv = transform(*xmlDoc, style, aOut, aErr);
|
||||
|
||||
delete xmlDoc;
|
||||
|
||||
|
@ -175,24 +174,24 @@ txStandaloneXSLTProcessor::transform(nsACString& aXMLPath,
|
|||
* or an error is returned.
|
||||
*/
|
||||
nsresult
|
||||
txStandaloneXSLTProcessor::transform(Document* aXMLDoc, ostream& aOut,
|
||||
txStandaloneXSLTProcessor::transform(txXPathNode& aXMLDoc, ostream& aOut,
|
||||
ErrorObserver& aErr)
|
||||
{
|
||||
if (!aXMLDoc) {
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
}
|
||||
Document* xmlDoc;
|
||||
nsresult rv = txXPathNativeNode::getDocument(aXMLDoc, &xmlDoc);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// get stylesheet path
|
||||
nsAutoString stylePath, basePath;
|
||||
aXMLDoc->getBaseURI(basePath);
|
||||
getHrefFromStylesheetPI(*aXMLDoc, stylePath);
|
||||
xmlDoc->getBaseURI(basePath);
|
||||
getHrefFromStylesheetPI(*xmlDoc, stylePath);
|
||||
txParsedURL base, ref, resolved;
|
||||
base.init(basePath);
|
||||
ref.init(stylePath);
|
||||
base.resolve(ref, resolved);
|
||||
|
||||
nsRefPtr<txStylesheet> style;
|
||||
nsresult rv = TX_CompileStylesheetPath(resolved, getter_AddRefs(style));
|
||||
rv = TX_CompileStylesheetPath(resolved, getter_AddRefs(style));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// transform
|
||||
|
@ -206,7 +205,7 @@ txStandaloneXSLTProcessor::transform(Document* aXMLDoc, ostream& aOut,
|
|||
* and prints the results to the given ostream argument
|
||||
*/
|
||||
nsresult
|
||||
txStandaloneXSLTProcessor::transform(Document* aSource,
|
||||
txStandaloneXSLTProcessor::transform(txXPathNode& aSource,
|
||||
txStylesheet* aStylesheet,
|
||||
ostream& aOut, ErrorObserver& aErr)
|
||||
{
|
||||
|
@ -356,7 +355,7 @@ void txStandaloneXSLTProcessor::parseStylesheetPI(const nsAFlatString& aData,
|
|||
}
|
||||
}
|
||||
|
||||
Document*
|
||||
txXPathNode*
|
||||
txStandaloneXSLTProcessor::parsePath(const nsACString& aPath, ErrorObserver& aErr)
|
||||
{
|
||||
NS_ConvertASCIItoUCS2 path(aPath);
|
||||
|
@ -367,7 +366,7 @@ txStandaloneXSLTProcessor::parsePath(const nsACString& aPath, ErrorObserver& aEr
|
|||
return 0;
|
||||
}
|
||||
// parse source
|
||||
Document* xmlDoc;
|
||||
txXPathNode* xmlDoc;
|
||||
nsAutoString errors;
|
||||
nsresult rv = txParseFromStream(xmlInput, path, errors, &xmlDoc);
|
||||
xmlInput.close();
|
||||
|
|
|
@ -122,7 +122,7 @@ public:
|
|||
* @param aErr error observer
|
||||
* @result NS_OK if transformation was successful
|
||||
*/
|
||||
nsresult transform(Document* aXMLDoc, ostream& aOut, ErrorObserver& aErr);
|
||||
nsresult transform(txXPathNode& aXMLDoc, ostream& aOut, ErrorObserver& aErr);
|
||||
|
||||
/**
|
||||
* Transform a XML document with the given stylesheet.
|
||||
|
@ -133,7 +133,7 @@ public:
|
|||
* @param aErr error observer
|
||||
* @result NS_OK if transformation was successful
|
||||
*/
|
||||
nsresult transform(Document* aXMLDoc, txStylesheet* aXSLNode,
|
||||
nsresult transform(txXPathNode& aXMLDoc, txStylesheet* aXSLNode,
|
||||
ostream& aOut, ErrorObserver& aErr);
|
||||
|
||||
protected:
|
||||
|
@ -160,7 +160,7 @@ protected:
|
|||
* @param aErr ErrorObserver
|
||||
* @result Document XML Document, or null on error
|
||||
*/
|
||||
static Document* parsePath(const nsACString& aPath, ErrorObserver& aErr);
|
||||
static txXPathNode* parsePath(const nsACString& aPath, ErrorObserver& aErr);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -136,14 +136,13 @@ txStylesheet::~txStylesheet()
|
|||
}
|
||||
|
||||
txInstruction*
|
||||
txStylesheet::findTemplate(Node* aNode,
|
||||
txStylesheet::findTemplate(const txXPathNode& aNode,
|
||||
const txExpandedName& aMode,
|
||||
txIMatchContext* aContext,
|
||||
ImportFrame* aImportedBy,
|
||||
ImportFrame** aImportFrame)
|
||||
{
|
||||
NS_ASSERTION(aImportFrame, "missing ImportFrame pointer");
|
||||
NS_ASSERTION(aNode, "missing node");
|
||||
|
||||
*aImportFrame = nsnull;
|
||||
txInstruction* matchTemplate = nsnull;
|
||||
|
@ -195,7 +194,7 @@ txStylesheet::findTemplate(Node* aNode,
|
|||
if (aMode.mLocalName) {
|
||||
aMode.mLocalName->ToString(mode);
|
||||
}
|
||||
aNode->getNodeName(nodeName);
|
||||
txXPathNodeUtils::getNodeName(aNode, nodeName);
|
||||
if (matchTemplate) {
|
||||
nsAutoString matchAttr;
|
||||
match->toString(matchAttr);
|
||||
|
@ -214,16 +213,16 @@ txStylesheet::findTemplate(Node* aNode,
|
|||
#endif
|
||||
|
||||
if (!matchTemplate) {
|
||||
switch(aNode->getNodeType()) {
|
||||
case Node::ELEMENT_NODE :
|
||||
case Node::DOCUMENT_NODE :
|
||||
switch (txXPathNodeUtils::getNodeType(aNode)) {
|
||||
case txXPathNodeType::ELEMENT_NODE:
|
||||
case txXPathNodeType::DOCUMENT_NODE:
|
||||
{
|
||||
matchTemplate = mContainerTemplate;
|
||||
break;
|
||||
}
|
||||
case Node::ATTRIBUTE_NODE :
|
||||
case Node::TEXT_NODE :
|
||||
case Node::CDATA_SECTION_NODE :
|
||||
case txXPathNodeType::ATTRIBUTE_NODE:
|
||||
case txXPathNodeType::TEXT_NODE:
|
||||
case txXPathNodeType::CDATA_SECTION_NODE:
|
||||
{
|
||||
matchTemplate = mCharactersTemplate;
|
||||
break;
|
||||
|
@ -276,37 +275,37 @@ txStylesheet::getKeyMap()
|
|||
}
|
||||
|
||||
PRBool
|
||||
txStylesheet::isStripSpaceAllowed(Node* aNode, txIMatchContext* aContext)
|
||||
txStylesheet::isStripSpaceAllowed(const txXPathNode& aNode, txIMatchContext* aContext)
|
||||
{
|
||||
PRInt32 frameCount = mStripSpaceTests.Count();
|
||||
if (!aNode || frameCount == 0) {
|
||||
if (frameCount == 0) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
switch (aNode->getNodeType()) {
|
||||
case Node::ELEMENT_NODE:
|
||||
{
|
||||
// check Whitespace stipping handling list against given Node
|
||||
PRInt32 i;
|
||||
for (i = 0; i < frameCount; ++i) {
|
||||
txStripSpaceTest* sst =
|
||||
NS_STATIC_CAST(txStripSpaceTest*, mStripSpaceTests[i]);
|
||||
if (sst->matches(aNode, aContext)) {
|
||||
if (sst->stripsSpace() &&
|
||||
!XMLUtils::getXMLSpacePreserve(aNode)) {
|
||||
return MB_TRUE;
|
||||
}
|
||||
return MB_FALSE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
txXPathTreeWalker walker(aNode);
|
||||
|
||||
PRUint16 nodeType = walker.getNodeType();
|
||||
if (nodeType == txXPathNodeType::TEXT_NODE ||
|
||||
nodeType == txXPathNodeType::CDATA_SECTION_NODE) {
|
||||
if (!txXPathNodeUtils::isWhitespace(aNode) || !walker.moveToParent()) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
case Node::TEXT_NODE:
|
||||
case Node::CDATA_SECTION_NODE:
|
||||
{
|
||||
if (!XMLUtils::isWhitespace(aNode))
|
||||
return MB_FALSE;
|
||||
return isStripSpaceAllowed(aNode->getParentNode(), aContext);
|
||||
nodeType = walker.getNodeType();
|
||||
}
|
||||
|
||||
if (nodeType != txXPathNodeType::ELEMENT_NODE) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
const txXPathNode& node = walker.getCurrentPosition();
|
||||
|
||||
// check Whitespace stipping handling list against given Node
|
||||
PRInt32 i;
|
||||
for (i = 0; i < frameCount; ++i) {
|
||||
txStripSpaceTest* sst =
|
||||
NS_STATIC_CAST(txStripSpaceTest*, mStripSpaceTests[i]);
|
||||
if (sst->matches(node, aContext)) {
|
||||
return sst->stripsSpace() && !XMLUtils::getXMLSpacePreserve(node);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ public:
|
|||
return mRefCnt;
|
||||
}
|
||||
|
||||
txInstruction* findTemplate(Node* aNode,
|
||||
txInstruction* findTemplate(const txXPathNode& aNode,
|
||||
const txExpandedName& aMode,
|
||||
txIMatchContext* aContext,
|
||||
ImportFrame* aImportedBy,
|
||||
|
@ -91,7 +91,8 @@ public:
|
|||
txOutputFormat* getOutputFormat();
|
||||
GlobalVariable* getGlobalVariable(const txExpandedName& aName);
|
||||
const txExpandedNameMap& getKeyMap();
|
||||
PRBool isStripSpaceAllowed(Node* aNode, txIMatchContext* aContext);
|
||||
PRBool isStripSpaceAllowed(const txXPathNode& aNode,
|
||||
txIMatchContext* aContext);
|
||||
|
||||
/**
|
||||
* Called by the stylesheet compiler once all stylesheets has been read.
|
||||
|
@ -212,12 +213,12 @@ class txStripSpaceTest {
|
|||
public:
|
||||
txStripSpaceTest(nsIAtom* aPrefix, nsIAtom* aLocalName, PRInt32 aNSID,
|
||||
MBool stripSpace)
|
||||
: mNameTest(aPrefix, aLocalName, aNSID, Node::ELEMENT_NODE),
|
||||
: mNameTest(aPrefix, aLocalName, aNSID, txXPathNodeType::ELEMENT_NODE),
|
||||
mStrips(stripSpace)
|
||||
{
|
||||
}
|
||||
|
||||
MBool matches(Node* aNode, txIMatchContext* aContext) {
|
||||
MBool matches(const txXPathNode& aNode, txIMatchContext* aContext) {
|
||||
return mNameTest.matches(aNode, aContext);
|
||||
}
|
||||
|
||||
|
|
|
@ -179,9 +179,6 @@ public:
|
|||
GenerateIdFunctionCall();
|
||||
|
||||
TX_DECL_FUNCTION;
|
||||
|
||||
private:
|
||||
static const char printfFmt[];
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "ExprResult.h"
|
||||
#include "txXSLTPatterns.h"
|
||||
#include "txIXPathContext.h"
|
||||
#include "txXPathTreeWalker.h"
|
||||
|
||||
nsresult txXSLTNumber::createNumber(Expr* aValueExpr, txPattern* aCountPattern,
|
||||
txPattern* aFromPattern, LevelType aLevel,
|
||||
|
@ -139,54 +140,54 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
|
|||
|
||||
txPattern* countPattern = aCountPattern;
|
||||
MBool ownsCountPattern = MB_FALSE;
|
||||
Node* currNode = aContext->getContextNode();
|
||||
const txXPathNode& currNode = aContext->getContextNode();
|
||||
|
||||
// Parse count- and from-attributes
|
||||
|
||||
if (!aCountPattern) {
|
||||
ownsCountPattern = MB_TRUE;
|
||||
txNodeTest* nodeTest = 0;
|
||||
switch (currNode->getNodeType()) {
|
||||
case Node::ELEMENT_NODE:
|
||||
switch (txXPathNodeUtils::getNodeType(currNode)) {
|
||||
case txXPathNodeType::ELEMENT_NODE:
|
||||
{
|
||||
nsCOMPtr<nsIAtom> localName;
|
||||
currNode->getLocalName(getter_AddRefs(localName));
|
||||
nodeTest = new txNameTest(0, localName,
|
||||
currNode->getNamespaceID(),
|
||||
Node::ELEMENT_NODE);
|
||||
nsCOMPtr<nsIAtom> localName =
|
||||
txXPathNodeUtils::getLocalName(currNode);
|
||||
PRInt32 namespaceID = txXPathNodeUtils::getNamespaceID(currNode);
|
||||
nodeTest = new txNameTest(0, localName, namespaceID,
|
||||
txXPathNodeType::ELEMENT_NODE);
|
||||
break;
|
||||
}
|
||||
case Node::TEXT_NODE:
|
||||
case Node::CDATA_SECTION_NODE:
|
||||
case txXPathNodeType::TEXT_NODE:
|
||||
case txXPathNodeType::CDATA_SECTION_NODE:
|
||||
{
|
||||
nodeTest = new txNodeTypeTest(txNodeTypeTest::TEXT_TYPE);
|
||||
break;
|
||||
}
|
||||
case Node::PROCESSING_INSTRUCTION_NODE:
|
||||
case txXPathNodeType::PROCESSING_INSTRUCTION_NODE:
|
||||
{
|
||||
txNodeTypeTest* typeTest;
|
||||
typeTest = new txNodeTypeTest(txNodeTypeTest::PI_TYPE);
|
||||
if (typeTest) {
|
||||
nsAutoString nodeName;
|
||||
currNode->getNodeName(nodeName);
|
||||
txXPathNodeUtils::getNodeName(currNode, nodeName);
|
||||
typeTest->setNodeName(nodeName);
|
||||
}
|
||||
nodeTest = typeTest;
|
||||
break;
|
||||
}
|
||||
case Node::COMMENT_NODE:
|
||||
case txXPathNodeType::COMMENT_NODE:
|
||||
{
|
||||
nodeTest = new txNodeTypeTest(txNodeTypeTest::COMMENT_TYPE);
|
||||
break;
|
||||
}
|
||||
case Node::DOCUMENT_NODE:
|
||||
case Node::ATTRIBUTE_NODE:
|
||||
case txXPathNodeType::DOCUMENT_NODE:
|
||||
case txXPathNodeType::ATTRIBUTE_NODE:
|
||||
default:
|
||||
{
|
||||
// this won't match anything as we walk up the tree
|
||||
// but it's what the spec says to do
|
||||
nodeTest = new txNameTest(0, txXPathAtoms::_asterix, 0,
|
||||
(Node::NodeType)currNode->getNodeType());
|
||||
txXPathNodeUtils::getNodeType(currNode));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -205,36 +206,33 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
|
|||
|
||||
// level = "single"
|
||||
if (aLevel == eLevelSingle) {
|
||||
Node* node = currNode;
|
||||
while (node) {
|
||||
if (aFromPattern && node != currNode &&
|
||||
aFromPattern->matches(node, aContext)) {
|
||||
txXPathTreeWalker walker(currNode);
|
||||
do {
|
||||
if (aFromPattern && !walker.isOnNode(currNode) &&
|
||||
aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (countPattern->matches(node, aContext)) {
|
||||
aValues.add(NS_INT32_TO_PTR(getSiblingCount(node, countPattern,
|
||||
if (countPattern->matches(walker.getCurrentPosition(), aContext)) {
|
||||
aValues.add(NS_INT32_TO_PTR(getSiblingCount(walker, countPattern,
|
||||
aContext)));
|
||||
break;
|
||||
}
|
||||
|
||||
node = node->getXPathParent();
|
||||
}
|
||||
} while (walker.moveToParent());
|
||||
|
||||
// Spec says to only match ancestors that are decendants of the
|
||||
// ancestor that matches the from-pattern, so keep going to make
|
||||
// sure that there is an ancestor that does.
|
||||
if (aFromPattern && aValues.getLength()) {
|
||||
node = node->getXPathParent();
|
||||
while (node) {
|
||||
if (aFromPattern->matches(node, aContext)) {
|
||||
PRBool hasParent;
|
||||
while ((hasParent = walker.moveToParent())) {
|
||||
if (aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
|
||||
break;
|
||||
}
|
||||
|
||||
node = node->getXPathParent();
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
if (!hasParent) {
|
||||
aValues.clear();
|
||||
}
|
||||
}
|
||||
|
@ -242,23 +240,21 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
|
|||
// level = "multiple"
|
||||
else if (aLevel == eLevelMultiple) {
|
||||
// find all ancestor-or-selfs that matches count until...
|
||||
Node* node = currNode;
|
||||
txXPathTreeWalker walker(currNode);
|
||||
MBool matchedFrom = MB_FALSE;
|
||||
while (node) {
|
||||
if (aFromPattern && node != currNode &&
|
||||
aFromPattern->matches(node, aContext)) {
|
||||
do {
|
||||
if (aFromPattern && !walker.isOnNode(currNode) &&
|
||||
aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
|
||||
//... we find one that matches from
|
||||
matchedFrom = MB_TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (countPattern->matches(node, aContext)) {
|
||||
aValues.add(NS_INT32_TO_PTR(getSiblingCount(node, countPattern,
|
||||
if (countPattern->matches(walker.getCurrentPosition(), aContext)) {
|
||||
aValues.add(NS_INT32_TO_PTR(getSiblingCount(walker, countPattern,
|
||||
aContext)));
|
||||
}
|
||||
|
||||
node = node->getXPathParent();
|
||||
}
|
||||
} while (walker.moveToParent());
|
||||
|
||||
// Spec says to only match ancestors that are decendants of the
|
||||
// ancestor that matches the from-pattern, so if none did then
|
||||
|
@ -269,23 +265,22 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
|
|||
}
|
||||
// level = "any"
|
||||
else if (aLevel == eLevelAny) {
|
||||
Node* node = currNode;
|
||||
PRInt32 value = 0;
|
||||
MBool matchedFrom = MB_FALSE;
|
||||
|
||||
while (node) {
|
||||
if (aFromPattern && node != currNode &&
|
||||
aFromPattern->matches(node, aContext)) {
|
||||
txXPathTreeWalker walker(currNode);
|
||||
do {
|
||||
if (aFromPattern && !walker.isOnNode(currNode) &&
|
||||
aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
|
||||
matchedFrom = MB_TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (countPattern->matches(node, aContext)) {
|
||||
if (countPattern->matches(walker.getCurrentPosition(), aContext)) {
|
||||
++value;
|
||||
}
|
||||
|
||||
node = getPrevInDocumentOrder(node);
|
||||
}
|
||||
} while (getPrevInDocumentOrder(walker));
|
||||
|
||||
// Spec says to only count nodes that follows the first node that
|
||||
// matches the from pattern. So so if none did then we shouldn't
|
||||
|
@ -439,34 +434,29 @@ txXSLTNumber::getCounters(Expr* aGroupSize, Expr* aGroupSeparator,
|
|||
}
|
||||
|
||||
PRInt32
|
||||
txXSLTNumber::getSiblingCount(Node* aNode, txPattern* aCountPattern,
|
||||
txXSLTNumber::getSiblingCount(txXPathTreeWalker& aWalker,
|
||||
txPattern* aCountPattern,
|
||||
txIMatchContext* aContext)
|
||||
{
|
||||
PRInt32 value = 1;
|
||||
Node* node = aNode->getPreviousSibling();
|
||||
|
||||
while (node) {
|
||||
if (aCountPattern->matches(node, aContext)) {
|
||||
while (aWalker.moveToPreviousSibling()) {
|
||||
if (aCountPattern->matches(aWalker.getCurrentPosition(), aContext)) {
|
||||
++value;
|
||||
}
|
||||
node = node->getPreviousSibling();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
Node*
|
||||
txXSLTNumber::getPrevInDocumentOrder(Node* aNode)
|
||||
PRBool
|
||||
txXSLTNumber::getPrevInDocumentOrder(txXPathTreeWalker& aWalker)
|
||||
{
|
||||
Node* prev = aNode->getPreviousSibling();
|
||||
if (prev) {
|
||||
Node* lastChild = prev->getLastChild();
|
||||
while (lastChild) {
|
||||
prev = lastChild;
|
||||
lastChild = prev->getLastChild();
|
||||
if (aWalker.moveToPreviousSibling()) {
|
||||
while (aWalker.moveToLastChild()) {
|
||||
// do nothing
|
||||
}
|
||||
return prev;
|
||||
return PR_TRUE;
|
||||
}
|
||||
return aNode->getXPathParent();
|
||||
return aWalker.moveToParent();
|
||||
}
|
||||
|
||||
#define TX_CHAR_RANGE(ch, a, b) if (ch < a) return MB_FALSE; \
|
||||
|
|
|
@ -44,10 +44,10 @@
|
|||
#include "nsString.h"
|
||||
|
||||
class Expr;
|
||||
class Node;
|
||||
class txPattern;
|
||||
class txIEvalContext;
|
||||
class txIMatchContext;
|
||||
class txXPathTreeWalker;
|
||||
|
||||
class txXSLTNumber {
|
||||
public:
|
||||
|
@ -74,11 +74,17 @@ private:
|
|||
txList& aCounters, nsAString& aHead,
|
||||
nsAString& aTail);
|
||||
|
||||
static PRInt32 getSiblingCount(Node* aNode, txPattern* aCountPattern,
|
||||
/**
|
||||
* getSiblingCount uses aWalker to walk the siblings of aWalker's current
|
||||
* position.
|
||||
*
|
||||
*/
|
||||
static PRInt32 getSiblingCount(txXPathTreeWalker& aWalker,
|
||||
txPattern* aCountPattern,
|
||||
txIMatchContext* aContext);
|
||||
|
||||
static Node* getPrevInDocumentOrder(Node* aNode);
|
||||
|
||||
static PRBool getPrevInDocumentOrder(txXPathTreeWalker& aWalker);
|
||||
|
||||
static MBool isAlphaNumeric(PRUnichar ch);
|
||||
};
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ double txUnionPattern::getDefaultPriority()
|
|||
* This should be called on the simple patterns for xsl:template,
|
||||
* but is fine for xsl:key and xsl:number
|
||||
*/
|
||||
MBool txUnionPattern::matches(Node* aNode, txIMatchContext* aContext)
|
||||
MBool txUnionPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
||||
{
|
||||
txListIterator iter(&mLocPathPatterns);
|
||||
while (iter.hasNext()) {
|
||||
|
@ -182,9 +182,9 @@ nsresult txLocPathPattern::addStep(txPattern* aPattern, MBool isChild)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
MBool txLocPathPattern::matches(Node* aNode, txIMatchContext* aContext)
|
||||
MBool txLocPathPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
||||
{
|
||||
NS_ASSERTION(aNode && mSteps.getLength(), "Internal error");
|
||||
NS_ASSERTION(mSteps.getLength(), "Internal error");
|
||||
|
||||
/*
|
||||
* The idea is to split up a path into blocks separated by descendant
|
||||
|
@ -205,40 +205,42 @@ MBool txLocPathPattern::matches(Node* aNode, txIMatchContext* aContext)
|
|||
step = (Step*)iter.previous();
|
||||
if (!step->pattern->matches(aNode, aContext))
|
||||
return MB_FALSE;
|
||||
Node* node = aNode->getXPathParent();
|
||||
|
||||
txXPathTreeWalker walker(aNode);
|
||||
PRBool hasParent = walker.moveToParent();
|
||||
|
||||
while (step->isChild) {
|
||||
step = (Step*)iter.previous();
|
||||
if (!step)
|
||||
return MB_TRUE; // all steps matched
|
||||
if (!node || !step->pattern->matches(node, aContext))
|
||||
if (!hasParent || !step->pattern->matches(walker.getCurrentPosition(), aContext))
|
||||
return MB_FALSE; // no more ancestors or no match
|
||||
|
||||
node = node->getXPathParent();
|
||||
hasParent = walker.moveToParent();
|
||||
}
|
||||
|
||||
// We have at least one // path separator
|
||||
Node *blockStart = node;
|
||||
txXPathTreeWalker blockWalker(walker);
|
||||
txListIterator blockIter(iter);
|
||||
|
||||
while ((step = (Step*)iter.previous())) {
|
||||
if (!node)
|
||||
if (!hasParent)
|
||||
return MB_FALSE; // There are more steps in the current block
|
||||
// than ancestors of the tested node
|
||||
|
||||
if (!step->pattern->matches(node, aContext)) {
|
||||
if (!step->pattern->matches(walker.getCurrentPosition(), aContext)) {
|
||||
// Didn't match. We restart at beginning of block using a new
|
||||
// start node
|
||||
iter = blockIter;
|
||||
blockStart = blockStart->getXPathParent();
|
||||
node = blockStart;
|
||||
hasParent = blockWalker.moveToParent();
|
||||
walker.moveTo(blockWalker);
|
||||
}
|
||||
else {
|
||||
node = node->getXPathParent();
|
||||
hasParent = walker.moveToParent();
|
||||
if (!step->isChild) {
|
||||
// We've matched an entire block. Set new start iter and start node
|
||||
blockIter = iter;
|
||||
blockStart = node;
|
||||
blockWalker.moveTo(walker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -288,9 +290,9 @@ txRootPattern::~txRootPattern()
|
|||
{
|
||||
}
|
||||
|
||||
MBool txRootPattern::matches(Node* aNode, txIMatchContext* aContext)
|
||||
MBool txRootPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
||||
{
|
||||
return aNode && (aNode->getNodeType() == Node::DOCUMENT_NODE);
|
||||
return (txXPathNodeUtils::getNodeType(aNode) == txXPathNodeType::DOCUMENT_NODE);
|
||||
}
|
||||
|
||||
double txRootPattern::getDefaultPriority()
|
||||
|
@ -339,19 +341,23 @@ txIdPattern::~txIdPattern()
|
|||
{
|
||||
}
|
||||
|
||||
MBool txIdPattern::matches(Node* aNode, txIMatchContext* aContext)
|
||||
MBool txIdPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
||||
{
|
||||
if (aNode->getNodeType() != Node::ELEMENT_NODE) {
|
||||
if (txXPathNodeUtils::getNodeType(aNode) != txXPathNodeType::ELEMENT_NODE) {
|
||||
return MB_FALSE;
|
||||
}
|
||||
|
||||
// Get a ID attribute, if there is
|
||||
nsAutoString value;
|
||||
#ifdef TX_EXE
|
||||
if (!((Element*)aNode)->getIDValue(value))
|
||||
return MB_FALSE;
|
||||
Element* elem;
|
||||
nsresult rv = txXPathNativeNode::getElement(aNode, &elem);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "So why claim it's an element above?");
|
||||
if (!elem->getIDValue(value)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
#else
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode->getNSObj());
|
||||
nsIContent* content = txXPathNativeNode::getContent(aNode);
|
||||
NS_ASSERTION(content, "a Element without nsIContent");
|
||||
if (!content) {
|
||||
return MB_FALSE;
|
||||
|
@ -405,16 +411,14 @@ txKeyPattern::~txKeyPattern()
|
|||
{
|
||||
}
|
||||
|
||||
MBool txKeyPattern::matches(Node* aNode, txIMatchContext* aContext)
|
||||
MBool txKeyPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
||||
{
|
||||
txExecutionState* es = (txExecutionState*)aContext->getPrivateContext();
|
||||
Document* contextDoc;
|
||||
if (aNode->getNodeType() == Node::DOCUMENT_NODE)
|
||||
contextDoc = (Document*)aNode;
|
||||
else
|
||||
contextDoc = aNode->getOwnerDocument();
|
||||
nsAutoPtr<txXPathNode> contextDoc(txXPathNodeUtils::getOwnerDocument(aNode));
|
||||
NS_ENSURE_TRUE(contextDoc, PR_FALSE);
|
||||
|
||||
nsRefPtr<txNodeSet> nodes;
|
||||
nsresult rv = es->getKeyNodes(mName, contextDoc, mValue, PR_TRUE,
|
||||
nsresult rv = es->getKeyNodes(mName, *contextDoc, mValue, PR_TRUE,
|
||||
getter_AddRefs(nodes));
|
||||
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
||||
|
||||
|
@ -459,17 +463,18 @@ txStepPattern::~txStepPattern()
|
|||
delete mNodeTest;
|
||||
}
|
||||
|
||||
MBool txStepPattern::matches(Node* aNode, txIMatchContext* aContext)
|
||||
MBool txStepPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
||||
{
|
||||
NS_ASSERTION(mNodeTest && aNode, "Internal error");
|
||||
if (!aNode)
|
||||
return MB_FALSE;
|
||||
NS_ASSERTION(mNodeTest, "Internal error");
|
||||
|
||||
if (!mNodeTest->matches(aNode, aContext))
|
||||
return MB_FALSE;
|
||||
|
||||
if (!mIsAttr && !aNode->getParentNode())
|
||||
txXPathTreeWalker walker(aNode);
|
||||
if ((!mIsAttr && walker.getNodeType() == txXPathNodeType::ATTRIBUTE_NODE) ||
|
||||
!walker.moveToParent()) {
|
||||
return MB_FALSE;
|
||||
}
|
||||
if (isEmpty()) {
|
||||
return MB_TRUE;
|
||||
}
|
||||
|
@ -497,25 +502,14 @@ MBool txStepPattern::matches(Node* aNode, txIMatchContext* aContext)
|
|||
nsresult rv = aContext->recycler()->getNodeSet(getter_AddRefs(nodes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
Node* parent = aNode->getXPathParent();
|
||||
if (mIsAttr) {
|
||||
NamedNodeMap* atts = parent->getAttributes();
|
||||
if (atts) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < atts->getLength(); i++) {
|
||||
Node* attr = atts->item(i);
|
||||
if (mNodeTest->matches(attr, aContext))
|
||||
nodes->append(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Node* tmpNode = parent->getFirstChild();
|
||||
while (tmpNode) {
|
||||
if (mNodeTest->matches(tmpNode, aContext))
|
||||
nodes->append(tmpNode);
|
||||
tmpNode = tmpNode->getNextSibling();
|
||||
PRBool hasNext = mIsAttr ? walker.moveToFirstAttribute() :
|
||||
walker.moveToFirstChild();
|
||||
while (hasNext) {
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
hasNext = mIsAttr ? walker.moveToNextAttribute() :
|
||||
walker.moveToNextSibling();
|
||||
}
|
||||
|
||||
txListIterator iter(&predicates);
|
||||
|
@ -539,7 +533,7 @@ MBool txStepPattern::matches(Node* aNode, txIMatchContext* aContext)
|
|||
// handle default, [position() == numberValue()]
|
||||
if ((double)predContext.position() ==
|
||||
exprResult->numberValue()) {
|
||||
Node* tmp = predContext.getContextNode();
|
||||
const txXPathNode& tmp = predContext.getContextNode();
|
||||
if (tmp == aNode)
|
||||
contextIsInPredicate = MB_TRUE;
|
||||
newNodes->append(tmp);
|
||||
|
@ -547,7 +541,7 @@ MBool txStepPattern::matches(Node* aNode, txIMatchContext* aContext)
|
|||
break;
|
||||
default:
|
||||
if (exprResult->booleanValue()) {
|
||||
Node* tmp = predContext.getContextNode();
|
||||
const txXPathNode& tmp = predContext.getContextNode();
|
||||
if (tmp == aNode)
|
||||
contextIsInPredicate = MB_TRUE;
|
||||
newNodes->append(tmp);
|
||||
|
@ -557,7 +551,7 @@ MBool txStepPattern::matches(Node* aNode, txIMatchContext* aContext)
|
|||
}
|
||||
// Move new NodeSet to the current one
|
||||
nodes->clear();
|
||||
nodes->append(newNodes);
|
||||
nodes->append(*newNodes);
|
||||
if (!contextIsInPredicate) {
|
||||
return MB_FALSE;
|
||||
}
|
||||
|
|
|
@ -53,7 +53,8 @@ public:
|
|||
/*
|
||||
* Determines whether this Pattern matches the given node.
|
||||
*/
|
||||
virtual MBool matches(Node* aNode, txIMatchContext* aContext) = 0;
|
||||
virtual MBool matches(const txXPathNode& aNode,
|
||||
txIMatchContext* aContext) = 0;
|
||||
|
||||
/*
|
||||
* Returns the default priority of this Pattern.
|
||||
|
@ -85,7 +86,7 @@ public:
|
|||
};
|
||||
|
||||
#define TX_DECL_PATTERN \
|
||||
MBool matches(Node* aNode, txIMatchContext* aContext); \
|
||||
MBool matches(const txXPathNode& aNode, txIMatchContext* aContext); \
|
||||
double getDefaultPriority(); \
|
||||
void toString(nsAString& aDest)
|
||||
#define TX_DECL_PATTERN2 \
|
||||
|
|
Загрузка…
Ссылка в новой задаче