From f555da27e14bf5d01320c132ce6efc98a2e1427c Mon Sep 17 00:00:00 2001 From: "axel%pike.org" Date: Wed, 2 Nov 2005 07:37:50 +0000 Subject: [PATCH] bug 113611, XPath and XSLT contexts. fixes bugs 96410, 102293, 92106, 110266, 116534 and a bunch of other cases not filed. This mostly fixes namespaces and some really bad speed issues by fixing the time when namespaces are resolved, how default priorities are computed and how templates are matched. HUGE PERFWIN :-) r=peterv, sr=jst --- content/xslt/src/base/txError.h | 5 + content/xslt/src/base/txErrorObserver.h | 28 +- .../xslt/src/base/txSimpleErrorObserver.cpp | 30 +- content/xslt/src/main/Makefile.in | 13 +- content/xslt/src/xpath/Makefile.in | 14 +- content/xslt/src/xpath/nsXPathEvaluator.cpp | 61 +- content/xslt/src/xpath/nsXPathEvaluator.h | 32 +- content/xslt/src/xpath/nsXPathExpression.cpp | 45 +- content/xslt/src/xpath/nsXPathExpression.h | 24 + content/xslt/src/xpath/txAdditiveExpr.cpp | 9 +- .../src/xpath/txAttributeValueTemplate.cpp | 5 +- content/xslt/src/xpath/txBooleanExpr.cpp | 9 +- .../xslt/src/xpath/txBooleanFunctionCall.cpp | 25 +- content/xslt/src/xpath/txExpr.h | 466 ++++--------- content/xslt/src/xpath/txExprParser.cpp | 261 +++++--- content/xslt/src/xpath/txExprParser.h | 78 +-- content/xslt/src/xpath/txFilterExpr.cpp | 47 +- content/xslt/src/xpath/txForwardContext.cpp | 81 +++ content/xslt/src/xpath/txForwardContext.h | 63 ++ content/xslt/src/xpath/txFunctionCall.cpp | 69 +- content/xslt/src/xpath/txFunctionLib.h | 128 +--- content/xslt/src/xpath/txIXPathContext.h | 150 +++++ content/xslt/src/xpath/txLocationStep.cpp | 150 ++--- .../xslt/src/xpath/txMultiplicativeExpr.cpp | 9 +- content/xslt/src/xpath/txNameTest.cpp | 106 +++ content/xslt/src/xpath/txNodeSetContext.cpp | 80 +++ content/xslt/src/xpath/txNodeSetContext.h | 74 +++ .../xslt/src/xpath/txNodeSetFunctionCall.cpp | 58 +- content/xslt/src/xpath/txNodeTypeTest.cpp | 121 ++++ .../xslt/src/xpath/txNumberFunctionCall.cpp | 21 +- content/xslt/src/xpath/txPathExpr.cpp | 127 +--- content/xslt/src/xpath/txPredicateList.cpp | 23 +- content/xslt/src/xpath/txRelationalExpr.cpp | 13 +- content/xslt/src/xpath/txRootExpr.cpp | 26 +- content/xslt/src/xpath/txSingleNodeContext.h | 101 +++ .../xslt/src/xpath/txStringFunctionCall.cpp | 71 +- content/xslt/src/xpath/txUnaryExpr.cpp | 4 +- content/xslt/src/xpath/txUnionExpr.cpp | 46 +- content/xslt/src/xpath/txVariableRefExpr.cpp | 50 +- content/xslt/src/xslt/Makefile.in | 2 + .../xslt/src/xslt/txCurrentFunctionCall.cpp | 23 +- .../xslt/src/xslt/txDocumentFunctionCall.cpp | 14 +- .../src/xslt/txElementAvailableFnCall.cpp | 25 +- .../src/xslt/txFormatNumberFunctionCall.cpp | 23 +- .../src/xslt/txFunctionAvailableFnCall.cpp | 10 +- .../src/xslt/txGenerateIdFunctionCall.cpp | 14 +- content/xslt/src/xslt/txKeyFunctionCall.cpp | 33 +- content/xslt/src/xslt/txNodeSorter.cpp | 27 +- content/xslt/src/xslt/txNodeSorter.h | 3 +- content/xslt/src/xslt/txPatternParser.cpp | 339 ++++++++++ content/xslt/src/xslt/txPatternParser.h | 71 ++ .../src/xslt/txSystemPropertyFunctionCall.cpp | 27 +- content/xslt/src/xslt/txXSLTFunctions.h | 67 +- content/xslt/src/xslt/txXSLTPatterns.cpp | 614 ++++++++++++++++++ content/xslt/src/xslt/txXSLTPatterns.h | 210 ++++++ 55 files changed, 2994 insertions(+), 1231 deletions(-) create mode 100644 content/xslt/src/xpath/txForwardContext.cpp create mode 100644 content/xslt/src/xpath/txForwardContext.h create mode 100644 content/xslt/src/xpath/txIXPathContext.h create mode 100644 content/xslt/src/xpath/txNameTest.cpp create mode 100644 content/xslt/src/xpath/txNodeSetContext.cpp create mode 100644 content/xslt/src/xpath/txNodeSetContext.h create mode 100644 content/xslt/src/xpath/txNodeTypeTest.cpp create mode 100644 content/xslt/src/xpath/txSingleNodeContext.h create mode 100644 content/xslt/src/xslt/txPatternParser.cpp create mode 100644 content/xslt/src/xslt/txPatternParser.h create mode 100644 content/xslt/src/xslt/txXSLTPatterns.cpp create mode 100644 content/xslt/src/xslt/txXSLTPatterns.h diff --git a/content/xslt/src/base/txError.h b/content/xslt/src/base/txError.h index 9fe0349753a3..e45914b939a9 100644 --- a/content/xslt/src/base/txError.h +++ b/content/xslt/src/base/txError.h @@ -68,4 +68,9 @@ typedef PRUint32 nsresult; #endif // TX_EXE +#define NS_ERROR_XPATH_EVAL_FAILED NS_ERROR_FAILURE +#define NS_ERROR_XPATH_PARSE_FAILED NS_ERROR_FAILURE +#define NS_ERROR_XPATH_INVALID_ARG NS_ERROR_INVALID_ARG +#define NS_ERROR_XSLT_INVALID_URL NS_ERROR_INVALID_ARG + #endif // __TX_ERROR diff --git a/content/xslt/src/base/txErrorObserver.h b/content/xslt/src/base/txErrorObserver.h index 826dac4414a9..ceb95dae458c 100644 --- a/content/xslt/src/base/txErrorObserver.h +++ b/content/xslt/src/base/txErrorObserver.h @@ -28,6 +28,7 @@ #include "baseutils.h" #include "TxString.h" +#include "txError.h" #include /** @@ -37,23 +38,26 @@ class ErrorObserver { public: - enum ErrorLevel {FATAL = 0, NORMAL, WARNING}; - /** * Default Destructor for ErrorObserver **/ virtual ~ErrorObserver() {}; /** - * Notifies this Error observer of a new error, with default - * level of NORMAL + * Notifies this Error observer of a new error aRes **/ - virtual void recieveError(String& errorMessage) = 0; + virtual void receiveError(const String& errorMessage, nsresult aRes) = 0; /** - * Notifies this Error observer of a new error using the given error level + * Notifies this Error observer of a new error, with default + * error code NS_ERROR_FAILURE **/ - virtual void recieveError(String& errorMessage, ErrorLevel level) = 0; + void receiveError(String& errorMessage) + { + receiveError(errorMessage, NS_ERROR_FAILURE); + } + + }; //-- ErrorObserver @@ -79,15 +83,9 @@ public: virtual ~SimpleErrorObserver() {}; /** - * Notifies this Error observer of a new error, with default - * level of NORMAL + * Notifies this Error observer of a new error aRes **/ - virtual void recieveError(String& errorMessage); - - /** - * Notifies this Error observer of a new error using the given error level - **/ - virtual void recieveError(String& errorMessage, ErrorLevel level); + void receiveError(const String& errorMessage, nsresult aRes); virtual void supressWarnings(MBool supress); diff --git a/content/xslt/src/base/txSimpleErrorObserver.cpp b/content/xslt/src/base/txSimpleErrorObserver.cpp index debfef44ccb6..f9d4716ca4eb 100644 --- a/content/xslt/src/base/txSimpleErrorObserver.cpp +++ b/content/xslt/src/base/txSimpleErrorObserver.cpp @@ -45,39 +45,21 @@ SimpleErrorObserver::SimpleErrorObserver(ostream& errStream) { hideWarnings = MB_FALSE; } //-- SimpleErrorObserver -/** - * Notifies this Error observer of a new error, with default - * level of NORMAL -**/ -void SimpleErrorObserver::recieveError(String& errorMessage) { -#ifdef TX_EXE - *errStream << "error: " << errorMessage << endl; - errStream->flush(); -#endif -} //-- recieveError - /** * Notifies this Error observer of a new error using the given error level **/ -void SimpleErrorObserver::recieveError(String& errorMessage, ErrorLevel level) { +void SimpleErrorObserver::receiveError(const String& errorMessage, + nsresult aRes) +{ #ifdef TX_EXE - switch ( level ) { - case ErrorObserver::FATAL : - *errStream << "fatal error: "; - break; - case ErrorObserver::WARNING : - if ( hideWarnings ) return; - *errStream << "warning: "; - break; - default: - *errStream << "error: "; - break; + if (NS_FAILED(aRes)) { + *errStream << "error: "; } *errStream << errorMessage << endl; errStream->flush(); #endif -} //-- recieveError +} void SimpleErrorObserver::supressWarnings(MBool supress) { this->hideWarnings = supress; diff --git a/content/xslt/src/main/Makefile.in b/content/xslt/src/main/Makefile.in index 7fa3b20586e9..13780723a9f0 100644 --- a/content/xslt/src/main/Makefile.in +++ b/content/xslt/src/main/Makefile.in @@ -61,19 +61,13 @@ OBJS =../base/ArrayList.$(OBJ_SUFFIX) \ ../xml/dom/standalone/ProcessingInstruction.$(OBJ_SUFFIX) \ ../xml/dom/standalone/Text.$(OBJ_SUFFIX) \ ../xpath/AdditiveExpr.$(OBJ_SUFFIX) \ - ../xpath/AttributeExpr.$(OBJ_SUFFIX) \ ../xpath/AttributeValueTemplate.$(OBJ_SUFFIX) \ - ../xpath/BasicNodeExpr.$(OBJ_SUFFIX) \ ../xpath/BooleanExpr.$(OBJ_SUFFIX) \ ../xpath/BooleanFunctionCall.$(OBJ_SUFFIX) \ ../xpath/BooleanResult.$(OBJ_SUFFIX) \ - ../xpath/ElementExpr.$(OBJ_SUFFIX) \ - ../xpath/ErrorFunctionCall.$(OBJ_SUFFIX) \ - ../xpath/Expr.$(OBJ_SUFFIX) \ ../xpath/ExprLexer.$(OBJ_SUFFIX) \ ../xpath/ExprLexerChars.$(OBJ_SUFFIX) \ ../xpath/ExprParser.$(OBJ_SUFFIX) \ - ../xpath/ExtensionFunctionCall.$(OBJ_SUFFIX) \ ../xpath/FilterExpr.$(OBJ_SUFFIX) \ ../xpath/FunctionCall.$(OBJ_SUFFIX) \ ../xpath/LocationStep.$(OBJ_SUFFIX) \ @@ -90,7 +84,10 @@ OBJS =../base/ArrayList.$(OBJ_SUFFIX) \ ../xpath/StringExpr.$(OBJ_SUFFIX) \ ../xpath/StringFunctionCall.$(OBJ_SUFFIX) \ ../xpath/StringResult.$(OBJ_SUFFIX) \ - ../xpath/TextExpr.$(OBJ_SUFFIX) \ + ../xpath/txNameTest.$(OBJ_SUFFIX) \ + ../xpath/txNodeTypeTest.$(OBJ_SUFFIX) \ + ../xpath/txForwardContext.$(OBJ_SUFFIX) \ + ../xpath/txNodeSetContext.$(OBJ_SUFFIX) \ ../xpath/UnionExpr.$(OBJ_SUFFIX) \ ../xpath/UnaryExpr.$(OBJ_SUFFIX) \ ../xpath/VariableRefExpr.$(OBJ_SUFFIX) \ @@ -111,6 +108,8 @@ OBJS =../base/ArrayList.$(OBJ_SUFFIX) \ ../xslt/txTextHandler.$(OBJ_SUFFIX) \ ../xslt/txTextOutput.$(OBJ_SUFFIX) \ ../xslt/txXMLOutput.$(OBJ_SUFFIX) \ + ../xslt/txXSLTPatterns.$(OBJ_SUFFIX) \ + ../xslt/txPatternParser.$(OBJ_SUFFIX) \ ../xslt/VariableBinding.$(OBJ_SUFFIX) \ ../xslt/XSLTProcessor.$(OBJ_SUFFIX) \ ../xslt/functions/CurrentFunctionCall.$(OBJ_SUFFIX) \ diff --git a/content/xslt/src/xpath/Makefile.in b/content/xslt/src/xpath/Makefile.in index 5a6e5ccbd3e4..31ea48150743 100644 --- a/content/xslt/src/xpath/Makefile.in +++ b/content/xslt/src/xpath/Makefile.in @@ -40,19 +40,13 @@ REQUIRES = string \ endif CPPSRCS = AdditiveExpr.cpp \ - AttributeExpr.cpp \ AttributeValueTemplate.cpp \ - BasicNodeExpr.cpp \ BooleanExpr.cpp \ BooleanFunctionCall.cpp \ BooleanResult.cpp \ - ElementExpr.cpp \ - ErrorFunctionCall.cpp \ - Expr.cpp \ ExprLexer.cpp \ ExprLexerChars.cpp \ ExprParser.cpp \ - ExtensionFunctionCall.cpp \ FilterExpr.cpp \ FunctionCall.cpp \ LocationStep.cpp \ @@ -69,7 +63,10 @@ CPPSRCS = AdditiveExpr.cpp \ StringExpr.cpp \ StringFunctionCall.cpp \ StringResult.cpp \ - TextExpr.cpp \ + txNameTest.cpp \ + txNodeTypeTest.cpp \ + txForwardContext.cpp \ + txNodeSetContext.cpp \ UnionExpr.cpp \ UnaryExpr.cpp \ VariableRefExpr.cpp \ @@ -87,6 +84,7 @@ include $(topsrcdir)/config/rules.mk INCLUDES += -I$(srcdir) -I$(srcdir)/../base \ -I$(srcdir)/../xml -I$(srcdir)/../xml/dom \ -I$(srcdir)/../xslt -I$(srcdir)/../xslt/util \ - -I$(srcdir)/../xslt/functions + -I$(srcdir)/../xslt/functions \ + -I$(srcdir) libs:: $(OBJS) diff --git a/content/xslt/src/xpath/nsXPathEvaluator.cpp b/content/xslt/src/xpath/nsXPathEvaluator.cpp index 72c33acec4a0..7b34b1f48853 100644 --- a/content/xslt/src/xpath/nsXPathEvaluator.cpp +++ b/content/xslt/src/xpath/nsXPathEvaluator.cpp @@ -45,6 +45,8 @@ #include "nsXPathNSResolver.h" #include "nsXPathResult.h" #include "ProcessorState.h" +#include "nsContentCID.h" +#include "ExprParser.h" NS_IMPL_ADDREF(nsXPathEvaluator) NS_IMPL_RELEASE(nsXPathEvaluator) @@ -69,8 +71,8 @@ nsXPathEvaluator::CreateExpression(const nsAString & aExpression, nsIDOMXPathExpression **aResult) { String expressionString(PromiseFlatString(aExpression).get()); - // XXX (pvdb) TODO Set the right resolver on the ExprParser - Expr* expression = mParser.createExpr(expressionString); + ParseContextImpl pContext(aResolver); + Expr* expression = ExprParser::createExpr(expressionString, &pContext); if (!expression) return NS_ERROR_DOM_INVALID_EXPRESSION_ERR; @@ -114,3 +116,58 @@ nsXPathEvaluator::Evaluate(const nsAString & aExpression, return expression->Evaluate(aContextNode, aType, aInResult, aResult); } + +/* + * Implementation of txIParseContext private to nsXPathEvaluator + * ParseContextImpl bases on a nsIDOMXPathNSResolver + */ + +static NS_DEFINE_CID(kNameSpaceManagerCID, NS_NAMESPACEMANAGER_CID); + +nsresult nsXPathEvaluator::ParseContextImpl::resolveNamespacePrefix + (txAtom* aPrefix, PRInt32& aID) +{ + nsAutoString prefix; + if (aPrefix) { + aPrefix->ToString(prefix); + } + nsAutoString ns; + nsresult rv = NS_OK; + if (mResolver) { + mResolver->LookupNamespaceURI(prefix, ns); + NS_ENSURE_SUCCESS(rv, rv); + } + + aID = kNameSpaceID_None; + if (ns.IsEmpty()) { + return NS_OK; + } + if (!mResolver) { + aID = kNameSpaceID_Unknown; + return NS_OK; + } + + if (!mNSMan) { + mNSMan = do_CreateInstance(kNameSpaceManagerCID); + if (!mNSMan) { + return NS_ERROR_FAILURE; + } + } + // get the namespaceID for the URI + + return mNSMan->RegisterNameSpace(ns, aID); +} + +nsresult nsXPathEvaluator::ParseContextImpl::resolveFunctionCall(txAtom* aName, + PRInt32 aID, + FunctionCall*& aFn) +{ + return NS_ERROR_XPATH_PARSE_FAILED; +} + +void nsXPathEvaluator::ParseContextImpl::receiveError(const String& aMsg, + nsresult aRes) +{ + mLastError = aRes; + // forward aMsg to console service? +} diff --git a/content/xslt/src/xpath/nsXPathEvaluator.h b/content/xslt/src/xpath/nsXPathEvaluator.h index f6e8e44e72e3..4e310f3ba417 100644 --- a/content/xslt/src/xpath/nsXPathEvaluator.h +++ b/content/xslt/src/xpath/nsXPathEvaluator.h @@ -41,7 +41,8 @@ #define nsXPathEvaluator_h__ #include "nsIDOMXPathEvaluator.h" -#include "ExprParser.h" +#include "txIXPathContext.h" +#include "nsINameSpaceManager.h" /** * A class for evaluating an XPath expression string @@ -59,7 +60,34 @@ public: NS_DECL_NSIDOMXPATHEVALUATOR private: - ExprParser mParser; + // txIParseContext implementation + class ParseContextImpl : public txIParseContext + { + public: + ParseContextImpl(nsIDOMXPathNSResolver* aResolver) + : mResolver(aResolver), mLastError(NS_OK) + { + } + + ~ParseContextImpl() + { + } + + nsresult getError() + { + return mLastError; + } + + nsresult resolveNamespacePrefix(txAtom* aPrefix, PRInt32& aID); + nsresult resolveFunctionCall(txAtom* aName, PRInt32 aID, + FunctionCall*& aFunction); + void receiveError(const String& aMsg, nsresult aRes); + + private: + nsIDOMXPathNSResolver* mResolver; + nsresult mLastError; + nsCOMPtr mNSMan; + }; }; /* d0a75e02-b5e7-11d5-a7f2-df109fb8a1fc */ diff --git a/content/xslt/src/xpath/nsXPathExpression.cpp b/content/xslt/src/xpath/nsXPathExpression.cpp index 2cca6bd2192b..735b210d2c1f 100644 --- a/content/xslt/src/xpath/nsXPathExpression.cpp +++ b/content/xslt/src/xpath/nsXPathExpression.cpp @@ -43,7 +43,6 @@ #include "nsIDOMClassInfo.h" #include "nsIDOMXPathNamespace.h" #include "nsXPathResult.h" -#include "ProcessorState.h" NS_IMPL_ADDREF(nsXPathExpression) NS_IMPL_RELEASE(nsXPathExpression) @@ -112,8 +111,8 @@ nsXPathExpression::Evaluate(nsIDOMNode *aContextNode, Document document(ownerDOMDocument); Node* node = document.createWrapper(aContextNode); - ProcessorState processorState; - ExprResult* exprResult = mExpression->evaluate(node, &processorState); + EvalContextImpl eContext(node); + ExprResult* exprResult = mExpression->evaluate(&eContext); NS_ENSURE_TRUE(exprResult, NS_ERROR_OUT_OF_MEMORY); PRUint16 resultType = aType; @@ -152,3 +151,43 @@ nsXPathExpression::Evaluate(nsIDOMNode *aContextNode, return CallQueryInterface(xpathResult, aResult); } + +/* + * Implementation of the txIEvalContext private to nsXPathExpression + * EvalContextImpl bases on only one context node and no variables + */ + +nsresult nsXPathExpression::EvalContextImpl::getVariable(PRInt32 aNamespace, + txAtom* aLName, + ExprResult*& aResult) +{ + aResult = 0; + return NS_ERROR_INVALID_ARG; +} + +MBool nsXPathExpression::EvalContextImpl::isStripSpaceAllowed(Node* aNode) +{ + return MB_FALSE; +} + +void nsXPathExpression::EvalContextImpl::receiveError(const String& aMsg, + nsresult aRes) +{ + mLastError = aRes; + // forward aMsg to console service? +} + +Node* nsXPathExpression::EvalContextImpl::getContextNode() +{ + return mNode; +} + +PRUint32 nsXPathExpression::EvalContextImpl::size() +{ + return 1; +} + +PRUint32 nsXPathExpression::EvalContextImpl::position() +{ + return 1; +} diff --git a/content/xslt/src/xpath/nsXPathExpression.h b/content/xslt/src/xpath/nsXPathExpression.h index 4f52676d5f7c..00faa19f2ccc 100644 --- a/content/xslt/src/xpath/nsXPathExpression.h +++ b/content/xslt/src/xpath/nsXPathExpression.h @@ -41,6 +41,7 @@ #define nsXPathExpression_h__ #include "nsIDOMXPathExpression.h" +#include "txIXPathContext.h" class Expr; @@ -61,6 +62,29 @@ public: private: Expr* mExpression; + + class EvalContextImpl : public txIEvalContext + { + public: + EvalContextImpl(Node* aContextNode) + :mNode(aContextNode), mLastError(NS_OK) + { + } + + ~EvalContextImpl() + { + } + + nsresult getError() + { + return mLastError; + } + + TX_DECL_EVAL_CONTEXT; + private: + Node* mNode; + nsresult mLastError; + }; }; #endif diff --git a/content/xslt/src/xpath/txAdditiveExpr.cpp b/content/xslt/src/xpath/txAdditiveExpr.cpp index cd440e7a503c..1088c38aa3b4 100644 --- a/content/xslt/src/xpath/txAdditiveExpr.cpp +++ b/content/xslt/src/xpath/txAdditiveExpr.cpp @@ -53,21 +53,20 @@ AdditiveExpr::~AdditiveExpr() { * for evaluation * @return the result of the evaluation **/ -ExprResult* AdditiveExpr::evaluate(Node* context, ContextState* cs) { - - +ExprResult* AdditiveExpr::evaluate(txIEvalContext* aContext) +{ double rightDbl = Double::NaN; ExprResult* exprRes = 0; if ( rightExpr ) { - exprRes = rightExpr->evaluate(context, cs); + exprRes = rightExpr->evaluate(aContext); if ( exprRes ) rightDbl = exprRes->numberValue(); delete exprRes; } double leftDbl = Double::NaN; if ( leftExpr ) { - exprRes = leftExpr->evaluate(context, cs); + exprRes = leftExpr->evaluate(aContext); if ( exprRes ) leftDbl = exprRes->numberValue(); delete exprRes; } diff --git a/content/xslt/src/xpath/txAttributeValueTemplate.cpp b/content/xslt/src/xpath/txAttributeValueTemplate.cpp index 2ea5341c0f2b..16d78c60ef5d 100644 --- a/content/xslt/src/xpath/txAttributeValueTemplate.cpp +++ b/content/xslt/src/xpath/txAttributeValueTemplate.cpp @@ -62,12 +62,13 @@ void AttributeValueTemplate::addExpr(Expr* expr) { * for evaluation * @return the result of the evaluation **/ -ExprResult* AttributeValueTemplate::evaluate(Node* context, ContextState* cs) { +ExprResult* AttributeValueTemplate::evaluate(txIEvalContext* aContext) +{ ListIterator* iter = expressions.iterator(); String result; while ( iter->hasNext() ) { Expr* expr = (Expr*)iter->next(); - ExprResult* exprResult = expr->evaluate(context, cs); + ExprResult* exprResult = expr->evaluate(aContext); exprResult->stringValue(result); delete exprResult; } diff --git a/content/xslt/src/xpath/txBooleanExpr.cpp b/content/xslt/src/xpath/txBooleanExpr.cpp index 526c287ce70c..acc91961dc6e 100644 --- a/content/xslt/src/xpath/txBooleanExpr.cpp +++ b/content/xslt/src/xpath/txBooleanExpr.cpp @@ -57,13 +57,12 @@ BooleanExpr::~BooleanExpr() { * for evaluation * @return the result of the evaluation **/ -ExprResult* BooleanExpr::evaluate(Node* context, ContextState* cs) { - - +ExprResult* BooleanExpr::evaluate(txIEvalContext* aContext) +{ MBool lval = MB_FALSE; ExprResult* exprRes = 0; if ( leftExpr ) { - exprRes = leftExpr->evaluate(context, cs); + exprRes = leftExpr->evaluate(aContext); if ( exprRes ) lval = exprRes->booleanValue(); delete exprRes; } @@ -75,7 +74,7 @@ ExprResult* BooleanExpr::evaluate(Node* context, ContextState* cs) { MBool rval = MB_FALSE; if ( rightExpr ) { - exprRes = rightExpr->evaluate(context, cs); + exprRes = rightExpr->evaluate(aContext); if ( exprRes ) rval = exprRes->booleanValue(); delete exprRes; } diff --git a/content/xslt/src/xpath/txBooleanFunctionCall.cpp b/content/xslt/src/xpath/txBooleanFunctionCall.cpp index 8ad9a3484bf7..761ffa31b134 100644 --- a/content/xslt/src/xpath/txBooleanFunctionCall.cpp +++ b/content/xslt/src/xpath/txBooleanFunctionCall.cpp @@ -29,6 +29,7 @@ #include "FunctionLib.h" #include "txAtoms.h" +#include "txIXPathContext.h" /** * Creates a default BooleanFunctionCall, which always evaluates to False @@ -62,27 +63,26 @@ BooleanFunctionCall::BooleanFunctionCall(BooleanFunctions aType) * for evaluation * @return the result of the evaluation **/ -ExprResult* BooleanFunctionCall::evaluate(Node* aContext, ContextState* aCs) +ExprResult* BooleanFunctionCall::evaluate(txIEvalContext* aContext) { ListIterator iter(¶ms); switch (mType) { case TX_BOOLEAN: { - if (!requireParams(1, 1, aCs)) + if (!requireParams(1, 1, aContext)) return new StringResult("error"); return new BooleanResult(evaluateToBoolean((Expr*)iter.next(), - aContext, - aCs)); + aContext)); } case TX_LANG: { - if (!requireParams(1, 1, aCs)) + if (!requireParams(1, 1, aContext)) return new StringResult("error"); String lang; - Node* node = aContext; + Node* node = aContext->getContextNode(); while (node) { if (node->getNodeType() == Node::ELEMENT_NODE) { Element* elem = (Element*)node; @@ -96,7 +96,7 @@ ExprResult* BooleanFunctionCall::evaluate(Node* aContext, ContextState* aCs) MBool result = MB_FALSE; if (node) { String arg; - evaluateToString((Expr*)iter.next(),aContext, aCs, arg); + evaluateToString((Expr*)iter.next(), aContext, arg); arg.toUpperCase(); // case-insensitive comparison lang.toUpperCase(); result = lang.indexOf(arg) == 0 && @@ -108,23 +108,22 @@ ExprResult* BooleanFunctionCall::evaluate(Node* aContext, ContextState* aCs) } case TX_NOT: { - if (!requireParams(1, 1, aCs)) + if (!requireParams(1, 1, aContext)) return new StringResult("error"); return new BooleanResult(!evaluateToBoolean((Expr*)iter.next(), - aContext, - aCs)); + aContext)); } case TX_TRUE: { - if (!requireParams(0, 0, aCs)) + if (!requireParams(0, 0, aContext)) return new StringResult("error"); return new BooleanResult(MB_TRUE); } case TX_FALSE: { - if (!requireParams(0, 0, aCs)) + if (!requireParams(0, 0, aContext)) return new StringResult("error"); return new BooleanResult(MB_FALSE); @@ -132,7 +131,7 @@ ExprResult* BooleanFunctionCall::evaluate(Node* aContext, ContextState* aCs) } String err("Internal error"); - aCs->recieveError(err); + aContext->receiveError(err, NS_ERROR_UNEXPECTED); return new StringResult("error"); } diff --git a/content/xslt/src/xpath/txExpr.h b/content/xslt/src/xpath/txExpr.h index f46a3e0d06ef..456591d7eb89 100644 --- a/content/xslt/src/xpath/txExpr.h +++ b/content/xslt/src/xpath/txExpr.h @@ -35,7 +35,7 @@ #ifndef TRANSFRMX_EXPR_H #define TRANSFRMX_EXPR_H - +#include "txError.h" #include "TxString.h" #include "ErrorObserver.h" #include "NodeSet.h" @@ -50,51 +50,12 @@ Much of this code was ported from XSL:P. */ -//necessary prototypes -class FunctionCall; - -typedef class Expr Pattern; -typedef class Expr PatternExpr; - - -/** - * The expression context and state class used when evaluating XPath Expressions. -**/ -class ContextState : public ErrorObserver { - -public: - - /** - * Returns the value of a given variable binding within the current scope - * @param the name to which the desired variable value has been bound - * @return the ExprResult which has been bound to the variable with - * the given name - **/ - virtual ExprResult* getVariable(String& name) = 0; - - /** - * Returns the Stack of context NodeSets - * @return the Stack of context NodeSets - **/ - virtual Stack* getNodeSetStack() = 0; - - virtual MBool isStripSpaceAllowed(Node* node) = 0; - - /** - * Returns a call to the function that has the given name. - * This method is used for XPath Extension Functions. - * @return the FunctionCall for the function with the given name. - **/ - virtual FunctionCall* resolveFunctionCall(const String& name) = 0; - - /** - * Returns the namespace URI for the given namespace prefix, this method should - * only be called for determining a namespace declared within the context - * (ie. the stylesheet) - **/ - virtual void getNameSpaceURIFromPrefix(const String& aPrefix, String& aNamespaceURI) = 0; -}; //-- ContextState - +/* + * necessary prototypes + */ +class txIParseContext; +class txIMatchContext; +class txIEvalContext; /** * A Base Class for all XSL Expressions @@ -106,7 +67,9 @@ public: /** * Virtual destructor, important for subclasses **/ - virtual ~Expr(); + virtual ~Expr() + { + } /** * Evaluates this Expr based on the given context node and processor state @@ -115,19 +78,7 @@ public: * for evaluation * @return the result of the evaluation **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs) = 0; - - /** - * Determines whether this Expr matches the given node within - * the given context - **/ - virtual MBool matches(Node* node, Node* context, ContextState* cs); - - /** - * Returns the default priority of this Expr based on the given Node, - * context Node, and ContextState. - **/ - virtual double getDefaultPriority(Node* node, Node* context, ContextState* cs); + virtual ExprResult* evaluate(txIEvalContext* aContext) = 0; /** * Returns the String representation of this Expr. @@ -141,6 +92,14 @@ public: }; //-- Expr +#define TX_DECL_EVALUATE \ + ExprResult* evaluate(txIEvalContext* aContext) + +#define TX_DECL_EXPR \ + TX_DECL_EVALUATE; \ + void toString(String& aDest) + + /** * This class represents a FunctionCall as defined by the XPath 1.0 * Recommendation. @@ -157,22 +116,22 @@ public: /** * Virtual methods from Expr **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs) = 0; - virtual MBool matches(Node* node, Node* context, ContextState* cs); - virtual double getDefaultPriority(Node* node, Node* context, ContextState* cs); + virtual ExprResult* evaluate(txIEvalContext* aContext) = 0; virtual void toString(String& dest); /** * Adds the given parameter to this FunctionCall's parameter list * @param expr the Expr to add to this FunctionCall's parameter list **/ - void addParam(Expr* expr); + nsresult addParam(Expr* aExpr); - virtual MBool requireParams(int paramCountMin, ContextState* cs); - - virtual MBool requireParams(int paramCountMin, - int paramCountMax, - ContextState* cs); + /* + * XXX txIEvalContext should be txIParseContest, bug 143291 + */ + virtual MBool requireParams(int aParamCountMin, txIEvalContext* aContext); + virtual MBool requireParams(int aParamCountMin, + int aParamCountMax, + txIEvalContext* aContext); protected: @@ -185,24 +144,24 @@ protected: * Evaluates the given Expression and converts its result to a String. * The value is appended to the given destination String */ - void evaluateToString(Expr* aExpr, Node* aContext, - ContextState* aCs, String& aDest); + void evaluateToString(Expr* aExpr, txIEvalContext* aContext, + String& aDest); /* * Evaluates the given Expression and converts its result to a number. */ - double evaluateToNumber(Expr* aExpr, Node* aContext, ContextState* aCs); + double evaluateToNumber(Expr* aExpr, txIEvalContext* aContext); /* * Evaluates the given Expression and converts its result to a boolean. */ - MBool evaluateToBoolean(Expr* aExpr, Node* aContext, ContextState* aCs); + MBool evaluateToBoolean(Expr* aExpr, txIEvalContext* aContext); /* * Evaluates the given Expression and converts its result to a NodeSet. * If the result is not a NodeSet NULL is returned. */ - NodeSet* evaluateToNodeSet(Expr* aExpr, Node* aContext, ContextState* aCs); + NodeSet* evaluateToNodeSet(Expr* aExpr, txIEvalContext* aContext); String name; }; //-- FunctionCall @@ -224,172 +183,91 @@ public: **/ void addExpr(Expr* expr); - /** - * Virtual methods from Expr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual void toString(String& str); + TX_DECL_EXPR; private: List expressions; }; -/** - * This class represents a NodeTestExpr as defined by the XSL - * Working Draft -**/ -class NodeExpr : public Expr { - +/* + * This class represents a NodeTest as defined by the XPath spec + */ +class txNodeTest +{ public: + virtual ~txNodeTest() {} + /* + * Virtual methods + * pretty much a txPattern, but not supposed to be used + * standalone. The NodeTest node() is different to the + * Pattern "node()" (document node isn't matched) + */ + virtual MBool matches(Node* aNode, txIMatchContext* aContext) = 0; + virtual double getDefaultPriority() = 0; + virtual void toString(String& aDest) = 0; +}; - //-- NodeExpr Types - //-- LF - changed from const short to enum - enum NodeExprType { - ATTRIBUTE_EXPR = 1, - ELEMENT_EXPR, - TEXT_EXPR, - COMMENT_EXPR, - PI_EXPR, - NODE_EXPR +#define TX_DECL_NODE_TEST \ + MBool matches(Node* aNode, txIMatchContext* aContext); \ + double getDefaultPriority(); \ + void toString(String& aDest) + +/* + * This class represents a NameTest as defined by the XPath spec + */ +class txNameTest : public txNodeTest +{ +public: + /* + * Creates a new txNameTest with the given type and the given + * principal node type + */ + txNameTest(txAtom* aPrefix, txAtom* aLocalName, PRInt32 aNSID, + Node::NodeType aNodeType); + + ~txNameTest(); + + TX_DECL_NODE_TEST; + +private: + txAtom* mPrefix; + txAtom* mLocalName; + PRInt32 mNamespace; + Node::NodeType mNodeType; +}; + +/* + * This class represents a NodeType as defined by the XPath spec + */ +class txNodeTypeTest : public txNodeTest +{ +public: + enum NodeType { + COMMENT_TYPE, + TEXT_TYPE, + PI_TYPE, + NODE_TYPE }; - virtual ~NodeExpr() {}; + /* + * Creates a new txNodeTypeTest of the given type + */ + txNodeTypeTest(NodeType aNodeType); - //------------------/ - //- Public Methods -/ - //------------------/ + ~txNodeTypeTest(); - /** - * Virtual methods from Expr - **/ - virtual MBool matches(Node* node, Node* context, ContextState* cs) = 0; - virtual double getDefaultPriority(Node* node, Node* context, ContextState* cs) = 0; - virtual void toString(String& dest) = 0; - -}; //-- NodeExpr - -/** - * This class represents a AttributeExpr as defined by the XSL - * Working Draft -**/ -class AttributeExpr : public NodeExpr { - -public: - - //------------------/ - //- Public Methods -/ - //------------------/ - - AttributeExpr(String& name); - - /** - * Virtual methods from NodeExpr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual MBool matches(Node* node, Node* context, ContextState* cs); - virtual double getDefaultPriority(Node* node, Node* context, ContextState* cs); - virtual void toString(String& dest); - -private: - - static const String WILD_CARD; - - String prefix; - String name; - MBool isNameWild; - MBool isNamespaceWild; - -}; //-- AttributeExpr - -/** - * -**/ -class BasicNodeExpr : public NodeExpr { - -public: - - //------------------/ - //- Public Methods -/ - //------------------/ - - /** - * Creates a new BasicNodeExpr of the given type - **/ - BasicNodeExpr(NodeExprType nodeExprType); - - /** + /* * Sets the name of the node to match. Only availible for pi nodes - **/ - void setNodeName(const String& name); + */ + void setNodeName(const String& aName); - /** - * Virtual methods from NodeExpr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual MBool matches(Node* node, Node* context, ContextState* cs); - virtual double getDefaultPriority(Node* node, Node* context, ContextState* cs); - virtual void toString(String& dest); + TX_DECL_NODE_TEST; private: - NodeExprType type; - String nodeName; - MBool nodeNameSet; -}; //-- BasicNodeExpr - -/** - * This class represents a ElementExpr as defined by the XSL - * Working Draft -**/ -class ElementExpr : public NodeExpr { - -public: - - //------------------/ - //- Public Methods -/ - //------------------/ - - ElementExpr(String& name); - - /** - * Virtual methods from NodeExpr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual double getDefaultPriority(Node* node, Node* context, ContextState* cs); - virtual MBool matches(Node* node, Node* context, ContextState* cs); - virtual void toString(String& dest); - -private: - - static const String WILD_CARD; - - String name; - MBool isNamespaceWild; - MBool isNameWild; - String prefix; - -}; //-- ElementExpr - -/** - * This class represents a TextExpr, which only matches any text node -**/ -class TextExpr : public NodeExpr { - -public: - - //------------------/ - //- Public Methods -/ - //------------------/ - - /** - * Virtual methods from NodeExpr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual MBool matches(Node* node, Node* context, ContextState* cs); - virtual double getDefaultPriority(Node* node, Node* context, ContextState* cs); - virtual void toString(String& dest); - -}; //-- TextExpr + NodeType mNodeType; + txAtom* mNodeName; +}; /** * Represents an ordered list of Predicates, @@ -415,8 +293,7 @@ public: **/ void add(Expr* expr); - - void evaluatePredicates(NodeSet* nodes, ContextState* cs); + void evaluatePredicates(NodeSet* aNodes, txIMatchContext* aContext); /** * returns true if this predicate list is empty @@ -433,7 +310,7 @@ public: **/ virtual void toString(String& dest); -private: +protected: //-- list of predicates List predicates; }; //-- PredicateList @@ -444,7 +321,7 @@ public: // Axis Identifier Types //-- LF changed from static const short to enum - enum _LocationStepType { + enum LocationStepType { ANCESTOR_AXIS = 0, ANCESTOR_OR_SELF_AXIS, ATTRIBUTE_AXIS, @@ -465,28 +342,24 @@ public: * @param nodeExpr the NodeExpr to use when matching Nodes * @param axisIdentifier the Axis Identifier in which to search for nodes **/ - LocationStep(NodeExpr* nodeExpr, short axisIdentifier); + LocationStep(txNodeTest* aNodeTest, LocationStepType aAxisIdentifier); /** * Destructor, will delete all predicates and the given NodeExpr **/ virtual ~LocationStep(); - /** - * Virtual methods from Expr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual MBool matches(Node* node, Node* context, ContextState* cs); - virtual double getDefaultPriority(Node* node, Node* context, ContextState* cs); - virtual void toString(String& dest); + TX_DECL_EXPR; private: - NodeExpr* nodeExpr; - short axisIdentifier; + txNodeTest* mNodeTest; + LocationStepType mAxisIdentifier; - void fromDescendants(Node* context, ContextState* cs, NodeSet* nodes); - void fromDescendantsRev(Node* context, ContextState* cs, NodeSet* nodes); + void fromDescendants(Node* node, txIMatchContext* aContext, + NodeSet* nodes); + void fromDescendantsRev(Node* node, txIMatchContext* aContext, + NodeSet* nodes); }; //-- LocationStep @@ -499,20 +372,14 @@ public: * Creates a new FilterExpr using the given Expr * @param expr the Expr to use for evaluation **/ - FilterExpr(Expr* expr); + FilterExpr(Expr* aExpr); /** * Destructor, will delete all predicates and the given Expr **/ virtual ~FilterExpr(); - /** - * Virtual methods from Expr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual MBool matches(Node* node, Node* context, ContextState* cs); - virtual double getDefaultPriority(Node* node, Node* context, ContextState* cs); - virtual void toString(String& dest); + TX_DECL_EXPR; private: Expr* expr; @@ -526,11 +393,7 @@ public: NumberExpr(double dbl); - /** - * Virtual methods from Expr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual void toString(String& str); + TX_DECL_EXPR; private: @@ -546,11 +409,7 @@ public: StringExpr(const String& value); - /** - * Virtual methods from Expr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual void toString(String& str); + TX_DECL_EXPR; private: @@ -575,11 +434,7 @@ public: AdditiveExpr(Expr* leftExpr, Expr* rightExpr, short op); ~AdditiveExpr(); - /** - * Virtual methods from Expr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual void toString(String& str); + TX_DECL_EXPR; private: short op; @@ -597,11 +452,7 @@ public: UnaryExpr(Expr* expr); ~UnaryExpr(); - /** - * Virtual methods from Expr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual void toString(String& str); + TX_DECL_EXPR; private: Expr* expr; @@ -621,11 +472,7 @@ public: BooleanExpr(Expr* leftExpr, Expr* rightExpr, short op); ~BooleanExpr(); - /** - * Virtual methods from Expr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual void toString(String& str); + TX_DECL_EXPR; private: short op; @@ -652,11 +499,7 @@ public: MultiplicativeExpr(Expr* leftExpr, Expr* rightExpr, short op); ~MultiplicativeExpr(); - /** - * Virtual methods from Expr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual void toString(String& str); + TX_DECL_EXPR; private: short op; @@ -692,11 +535,7 @@ public: RelationalExpr(Expr* leftExpr, Expr* rightExpr, short op); ~RelationalExpr(); - /** - * Virtual methods from Expr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual void toString(String& str); + TX_DECL_EXPR; private: short op; @@ -714,18 +553,16 @@ class VariableRefExpr : public Expr { public: - VariableRefExpr(const String& name); + VariableRefExpr(txAtom* aPrefix, txAtom* aLocalName, PRInt32 aNSID); + ~VariableRefExpr(); - /** - * Virtual methods from Expr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual void toString(String& str); + TX_DECL_EXPR; private: - String name; - -}; //-- VariableRefExpr + txAtom* mPrefix; + txAtom* mLocalName; + PRInt32 mNamespace; +}; /** * Represents a PathExpr @@ -755,32 +592,25 @@ public: **/ void addExpr(Expr* expr, PathOperator pathOp); - /** - * Virtual methods from Expr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual MBool matches(Node* node, Node* context, ContextState* cs); - virtual double getDefaultPriority(Node* node, Node* context, ContextState* cs); - virtual void toString(String& dest); + TX_DECL_EXPR; private: - + static const String RTF_INVALID_OP; + static const String NODESET_EXPECTED; struct PathExprItem { Expr* expr; PathOperator pathOp; }; - List expressions; + List expressions; - /** - * Selects from the descendants of the context node - * all nodes that match the Expr - * -- this will be moving to a Utility class - **/ - void evalDescendants(Expr* expr, - Node* context, - ContextState* cs, - NodeSet* resNodes); + /* + * Selects from the descendants of the context node + * all nodes that match the Expr + */ + void evalDescendants(Expr* aStep, Node* aNode, + txIMatchContext* aContext, + NodeSet* resNodes); }; //-- PathExpr @@ -797,13 +627,7 @@ public: */ RootExpr(MBool aSerialize); - /** - * Virtual methods from Expr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual MBool matches(Node* node, Node* context, ContextState* cs); - virtual double getDefaultPriority(Node* node, Node* context, ContextState* cs); - virtual void toString(String& dest); + TX_DECL_EXPR; private: // When a RootExpr is used in a PathExpr it shouldn't be serialized @@ -834,13 +658,7 @@ public: **/ void addExpr(Expr* expr); - /** - * Virtual methods from Expr - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - virtual MBool matches(Node* node, Node* context, ContextState* cs); - virtual double getDefaultPriority(Node* node, Node* context, ContextState* cs); - virtual void toString(String& dest); + TX_DECL_EXPR; private: diff --git a/content/xslt/src/xpath/txExprParser.cpp b/content/xslt/src/xpath/txExprParser.cpp index 3631e3fe2158..a3949738d6de 100644 --- a/content/xslt/src/xpath/txExprParser.cpp +++ b/content/xslt/src/xpath/txExprParser.cpp @@ -41,25 +41,16 @@ #include "ExprParser.h" #include "FunctionLib.h" #include "Names.h" - -/** - * Creates a new ExprParser -**/ -ExprParser::ExprParser() {}; - -/** - * Default Destructor -**/ -ExprParser::~ExprParser() {}; +#include "txAtoms.h" +#include "txIXPathContext.h" /** * Creates an Attribute Value Template using the given value * This should move to XSLProcessor class **/ AttributeValueTemplate* ExprParser::createAttributeValueTemplate - (const String& attValue) + (const String& attValue, txIParseContext* aContext) { - AttributeValueTemplate* avt = new AttributeValueTemplate(); if (attValue.isEmpty()) @@ -116,7 +107,8 @@ AttributeValueTemplate* ExprParser::createAttributeValueTemplate case '}': if (inExpr) { inExpr = MB_FALSE; - Expr* expr = createExpr(buffer); + ExprLexer lexer(buffer); + Expr* expr = createExpr(lexer, aContext); if (!expr) { delete avt; return 0; @@ -154,18 +146,14 @@ AttributeValueTemplate* ExprParser::createAttributeValueTemplate } //-- createAttributeValueTemplate -Expr* ExprParser::createExpr(const String& aExpression) +Expr* ExprParser::createExpr(const String& aExpression, + txIParseContext* aContext) { ExprLexer lexer(aExpression); - return createExpr(lexer); + Expr* expr = createExpr(lexer, aContext); + return expr; } //-- createExpr -Pattern* ExprParser::createPattern(const String& aPattern) -{ - ExprLexer lexer(aPattern); - return createUnionExpr(lexer); -} //-- createPatternExpr - //--------------------/ //- Private Methods -/ //-------------------/ @@ -221,8 +209,8 @@ Expr* ExprParser::createBinaryExpr (Expr* left, Expr* right, Token* op) { } //-- createBinaryExpr -Expr* ExprParser::createExpr(ExprLexer& lexer) { - +Expr* ExprParser::createExpr(ExprLexer& lexer, txIParseContext* aContext) +{ MBool done = MB_FALSE; Expr* expr = 0; @@ -238,7 +226,7 @@ Expr* ExprParser::createExpr(ExprLexer& lexer) { lexer.nextToken(); } - expr = createUnionExpr(lexer); + expr = createUnionExpr(lexer, aContext); if (!expr) break; @@ -299,21 +287,33 @@ Expr* ExprParser::createExpr(ExprLexer& lexer) { } //-- createExpr -Expr* ExprParser::createFilterExpr(ExprLexer& lexer) { - +Expr* ExprParser::createFilterExpr(ExprLexer& lexer, txIParseContext* aContext) +{ Token* tok = lexer.nextToken(); Expr* expr = 0; switch (tok->type) { case Token::FUNCTION_NAME : lexer.pushBack(); - expr = createFunctionCall(lexer); + expr = createFunctionCall(lexer, aContext); break; case Token::VAR_REFERENCE : - expr = new VariableRefExpr(tok->value); + { + txAtom *prefix, *lName; + PRInt32 nspace; + nsresult rv = resolveQName(tok->value, prefix, aContext, + lName, nspace); + if (NS_FAILED(rv)) { + // XXX error report namespace resolve failed + return 0; + } + expr = new VariableRefExpr(prefix, lName, nspace); + TX_IF_RELEASE_ATOM(prefix); + TX_IF_RELEASE_ATOM(lName); + } break; case Token::L_PAREN: - expr = createExpr(lexer); + expr = createExpr(lexer, aContext); if (!expr) return 0; @@ -347,7 +347,7 @@ Expr* ExprParser::createFilterExpr(ExprLexer& lexer) { FilterExpr* filterExpr = new FilterExpr(expr); //-- handle predicates - if (!parsePredicates(filterExpr, lexer)) { + if (!parsePredicates(filterExpr, lexer, aContext)) { delete filterExpr; return 0; } @@ -358,8 +358,9 @@ Expr* ExprParser::createFilterExpr(ExprLexer& lexer) { } //-- createFilterExpr -FunctionCall* ExprParser::createFunctionCall(ExprLexer& lexer) { - +Expr* ExprParser::createFunctionCall(ExprLexer& lexer, + txIParseContext* aContext) +{ FunctionCall* fnCall = 0; Token* tok = lexer.nextToken(); @@ -368,11 +369,11 @@ FunctionCall* ExprParser::createFunctionCall(ExprLexer& lexer) { return 0; } - String fnName = tok->value; - //-- compare function names //-- * we should hash these names for speed + nsresult rv = NS_OK; + if (XPathNames::BOOLEAN_FN.isEqual(tok->value)) { fnCall = new BooleanFunctionCall(BooleanFunctionCall::TX_BOOLEAN); } @@ -455,24 +456,44 @@ FunctionCall* ExprParser::createFunctionCall(ExprLexer& lexer) { fnCall = new NumberFunctionCall(NumberFunctionCall::FLOOR); } else { - //-- Most likely an Extension Function, or error, but it's - //-- not our job to report an invalid function call here - fnCall = new ExtensionFunctionCall(fnName); + txAtom *prefix, *lName; + PRInt32 namespaceID; + rv = resolveQName(tok->value, prefix, aContext, lName, namespaceID); + if (NS_FAILED(rv)) { + // XXX error report namespace resolve failed + return 0; + } + rv = aContext->resolveFunctionCall(lName, namespaceID, fnCall); + TX_IF_RELEASE_ATOM(prefix); + TX_IF_RELEASE_ATOM(lName); + if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) { + // XXX report error unknown function call + return 0; + } } //-- handle parametes - if (!parseParameters(fnCall, lexer)) { + if (!parseParameters(fnCall, lexer, aContext)) { delete fnCall; return 0; } + + if (rv == NS_ERROR_NOT_IMPLEMENTED) { + NS_ASSERTION(!fnCall, "Now is it implemented or not?"); + String err(tok->value); + err.append(" not implemented."); + return new StringExpr(err); + } + return fnCall; } //-- createFunctionCall -LocationStep* ExprParser::createLocationStep(ExprLexer& lexer) { - +LocationStep* ExprParser::createLocationStep(ExprLexer& lexer, + txIParseContext* aContext) +{ //-- child axis is default - short axisIdentifier = LocationStep::CHILD_AXIS; - NodeExpr* nodeExpr = 0; + LocationStep::LocationStepType axisIdentifier = LocationStep::CHILD_AXIS; + txNodeTest* nodeTest = 0; //-- get Axis Identifier or AbbreviatedStep, if present Token* tok = lexer.peek(); @@ -536,44 +557,78 @@ LocationStep* ExprParser::createLocationStep(ExprLexer& lexer) { //-- eat token lexer.nextToken(); axisIdentifier = LocationStep::PARENT_AXIS; - nodeExpr = new BasicNodeExpr(NodeExpr::NODE_EXPR); + nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE); + if (!nodeTest) { + //XXX out of memory + return 0; + } break; case Token::SELF_NODE : //-- eat token lexer.nextToken(); axisIdentifier = LocationStep::SELF_AXIS; - nodeExpr = new BasicNodeExpr(NodeExpr::NODE_EXPR); + nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE); + if (!nodeTest) { + //XXX out of memory + return 0; + } break; default: break; } - //-- get NodeTest unless AbbreviatedStep was found - if (!nodeExpr) { + //-- get NodeTest unless an AbbreviatedStep was found + if (!nodeTest) { tok = lexer.nextToken(); switch (tok->type) { case Token::CNAME : - // NameTest - // XXX Namespace: handle namespaces here - if (axisIdentifier == LocationStep::ATTRIBUTE_AXIS) - nodeExpr = new AttributeExpr(tok->value); - else - nodeExpr = new ElementExpr(tok->value); + { + // resolve QName + txAtom *prefix, *lName; + PRInt32 nspace; + nsresult rv = resolveQName(tok->value, prefix, aContext, + lName, nspace); + if (NS_FAILED(rv)) { + // XXX error report namespace resolve failed + return 0; + } + switch (axisIdentifier) { + case LocationStep::ATTRIBUTE_AXIS: + nodeTest = new txNameTest(prefix, lName, nspace, + Node::ATTRIBUTE_NODE); + break; + default: + nodeTest = new txNameTest(prefix, lName, nspace, + Node::ELEMENT_NODE); + break; + } + TX_IF_RELEASE_ATOM(prefix); + TX_IF_RELEASE_ATOM(lName); + } + if (!nodeTest) { + //XXX ErrorReport: out of memory + return 0; + } break; default: lexer.pushBack(); - nodeExpr = createNodeExpr(lexer); - if (!nodeExpr) { + nodeTest = createNodeTypeTest(lexer); + if (!nodeTest) { return 0; } } } - LocationStep* lstep = new LocationStep(nodeExpr, axisIdentifier); + LocationStep* lstep = new LocationStep(nodeTest, axisIdentifier); + if (!lstep) { + //XXX out of memory + delete nodeTest; + return 0; + } //-- handle predicates - if (!parsePredicates(lstep, lexer)) { + if (!parsePredicates(lstep, lexer, aContext)) { delete lstep; return 0; } @@ -585,59 +640,62 @@ LocationStep* ExprParser::createLocationStep(ExprLexer& lexer) { * This method only handles comment(), text(), processing-instructing() and node() * **/ -NodeExpr* ExprParser::createNodeExpr(ExprLexer& lexer) { +txNodeTypeTest* ExprParser::createNodeTypeTest(ExprLexer& lexer) { - NodeExpr* nodeExpr = 0; + txNodeTypeTest* nodeTest = 0; Token* nodeTok = lexer.nextToken(); switch (nodeTok->type) { case Token::COMMENT: - nodeExpr = new BasicNodeExpr(NodeExpr::COMMENT_EXPR); + nodeTest = new txNodeTypeTest(txNodeTypeTest::COMMENT_TYPE); break; case Token::NODE : - nodeExpr = new BasicNodeExpr(NodeExpr::NODE_EXPR); + nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE); break; case Token::PROC_INST : - nodeExpr = new BasicNodeExpr(NodeExpr::PI_EXPR); + nodeTest = new txNodeTypeTest(txNodeTypeTest::PI_TYPE); break; case Token::TEXT : - nodeExpr = new TextExpr(); + nodeTest = new txNodeTypeTest(txNodeTypeTest::TEXT_TYPE); break; default: lexer.pushBack(); // XXX ErrorReport: unexpected token return 0; - break; + } + if (!nodeTest) { + //XXX out of memory + return 0; } if (lexer.nextToken()->type != Token::L_PAREN) { lexer.pushBack(); //XXX ErrorReport: left parenthesis expected - delete nodeExpr; + delete nodeTest; return 0; } if (nodeTok->type == Token::PROC_INST && lexer.peek()->type == Token::LITERAL) { Token* tok = lexer.nextToken(); - ((BasicNodeExpr*)nodeExpr)->setNodeName(tok->value); + nodeTest->setNodeName(tok->value); } if (lexer.nextToken()->type != Token::R_PAREN) { lexer.pushBack(); //XXX ErrorReport: right parenthesis expected (or literal for pi) - delete nodeExpr; + delete nodeTest; return 0; } - return nodeExpr; -} //-- createNodeExpr + return nodeTest; +} //-- createNodeTypeTest /** * Creates a PathExpr using the given ExprLexer * @param lexer the ExprLexer for retrieving Tokens **/ -Expr* ExprParser::createPathExpr(ExprLexer& lexer) { - +Expr* ExprParser::createPathExpr(ExprLexer& lexer, txIParseContext* aContext) +{ Expr* expr = 0; Token* tok = lexer.peek(); @@ -655,10 +713,10 @@ Expr* ExprParser::createPathExpr(ExprLexer& lexer) { if (tok->type != Token::PARENT_OP && tok->type != Token::ANCESTOR_OP) { if (isFilterExprToken(tok)) { - expr = createFilterExpr(lexer); + expr = createFilterExpr(lexer, aContext); } else - expr = createLocationStep(lexer); + expr = createLocationStep(lexer, aContext); if (!expr) return 0; @@ -702,7 +760,7 @@ Expr* ExprParser::createPathExpr(ExprLexer& lexer) { return pathExpr; } - expr = createLocationStep(lexer); + expr = createLocationStep(lexer, aContext); if (!expr) { delete pathExpr; return 0; @@ -719,9 +777,9 @@ Expr* ExprParser::createPathExpr(ExprLexer& lexer) { * XXX temporary use as top of XSLT Pattern * @param lexer the ExprLexer for retrieving Tokens **/ -Expr* ExprParser::createUnionExpr(ExprLexer& lexer) { - - Expr* expr = createPathExpr(lexer); +Expr* ExprParser::createUnionExpr(ExprLexer& lexer, txIParseContext* aContext) +{ + Expr* expr = createPathExpr(lexer, aContext); if (!expr) return 0; @@ -734,7 +792,7 @@ Expr* ExprParser::createUnionExpr(ExprLexer& lexer) { while (lexer.peek()->type == Token::UNION_OP) { lexer.nextToken(); //-- eat token - expr = createPathExpr(lexer); + expr = createPathExpr(lexer, aContext); if (!expr) { delete unionExpr; return 0; @@ -791,13 +849,14 @@ MBool ExprParser::isNodeTypeToken(Token* token) { * @param lexer the ExprLexer to use for parsing tokens * @return 0 if successful, or a String pointer to the error message **/ -MBool ExprParser::parsePredicates(PredicateList* predicateList, ExprLexer& lexer) { - +MBool ExprParser::parsePredicates(PredicateList* predicateList, + ExprLexer& lexer, txIParseContext* aContext) +{ while (lexer.peek()->type == Token::L_BRACKET) { //-- eat Token lexer.nextToken(); - Expr* expr = createExpr(lexer); + Expr* expr = createExpr(lexer, aContext); if (!expr) return MB_FALSE; @@ -822,8 +881,9 @@ MBool ExprParser::parsePredicates(PredicateList* predicateList, ExprLexer& lexer * @param lexer the ExprLexer to use for parsing tokens * @return MB_TRUE if successful, or a MB_FALSE otherwise **/ -MBool ExprParser::parseParameters(FunctionCall* fnCall, ExprLexer& lexer) { - +MBool ExprParser::parseParameters(FunctionCall* fnCall, ExprLexer& lexer, + txIParseContext* aContext) +{ if (lexer.nextToken()->type != Token::L_PAREN) { lexer.pushBack(); //XXX ErrorReport: left parenthesis expected @@ -836,11 +896,12 @@ MBool ExprParser::parseParameters(FunctionCall* fnCall, ExprLexer& lexer) { } while (1) { - Expr* expr = createExpr(lexer); + Expr* expr = createExpr(lexer, aContext); if (!expr) return MB_FALSE; - fnCall->addParam(expr); + if (fnCall) + fnCall->addParam(expr); switch (lexer.nextToken()->type) { case Token::R_PAREN : @@ -887,5 +948,35 @@ short ExprParser::precedenceLevel(short tokenType) { break; } return 0; -} //-- precedenceLevel +} +nsresult ExprParser::resolveQName(const String& aQName, + txAtom*& aPrefix, txIParseContext* aContext, + txAtom*& aLocalName, PRInt32& aNamespace) +{ + aNamespace = kNameSpaceID_None; + String prefix, lName; + int idx = aQName.indexOf(':'); + if (idx > 0) { + aQName.subString(0, idx, prefix); + aPrefix = TX_GET_ATOM(prefix); + if (!aPrefix) { + return NS_ERROR_OUT_OF_MEMORY; + } + aQName.subString(idx + 1, lName); + aLocalName = TX_GET_ATOM(lName); + if (!aLocalName) { + TX_RELEASE_ATOM(aPrefix); + aPrefix = 0; + return NS_ERROR_OUT_OF_MEMORY; + } + return aContext->resolveNamespacePrefix(aPrefix, aNamespace); + } + // the lexer dealt with idx == 0 + aPrefix = 0; + aLocalName = TX_GET_ATOM(aQName); + if (!aLocalName) { + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} diff --git a/content/xslt/src/xpath/txExprParser.h b/content/xslt/src/xpath/txExprParser.h index 432a8193a141..a0187df216c4 100644 --- a/content/xslt/src/xpath/txExprParser.h +++ b/content/xslt/src/xpath/txExprParser.h @@ -36,59 +36,61 @@ #include "ExprLexer.h" #include "Expr.h" #include "List.h" +class txIParseContext; -class ExprParser { - +class ExprParser +{ public: - /** - * Creates a new ExprParser - **/ - ExprParser(); - - /** - * destroys the ExprParser - **/ - ~ExprParser(); - - Expr* createExpr(const String& aExpression); - Pattern* createPattern(const String& aPattern); + static Expr* createExpr(const String& aExpression, + txIParseContext* aContext); /** * Creates an Attribute Value Template using the given value **/ - AttributeValueTemplate* createAttributeValueTemplate(const String& attValue); + static AttributeValueTemplate* createAttributeValueTemplate + (const String& attValue, txIParseContext* aContext); -private: - - - Expr* createBinaryExpr (Expr* left, Expr* right, Token* op); - Expr* createExpr (ExprLexer& lexer); - Expr* createFilterExpr (ExprLexer& lexer); - FunctionCall* createFunctionCall (ExprLexer& lexer); - LocationStep* createLocationStep (ExprLexer& lexer); - NodeExpr* createNodeExpr (ExprLexer& lexer); - Expr* createPathExpr (ExprLexer& lexer); - Expr* createUnionExpr (ExprLexer& lexer); - - MBool isFilterExprToken (Token* tok); - MBool isLocationStepToken (Token* tok); - MBool isNodeTypeToken (Token* tok); - - static short precedenceLevel (short tokenType); +protected: + static Expr* createBinaryExpr(Expr* left, Expr* right, Token* op); + static Expr* createExpr(ExprLexer& lexer, txIParseContext* aContext); + static Expr* createFilterExpr(ExprLexer& lexer, txIParseContext* aContext); + static Expr* createFunctionCall(ExprLexer& lexer, + txIParseContext* aContext); + static LocationStep* createLocationStep(ExprLexer& lexer, + txIParseContext* aContext); + static txNodeTypeTest* createNodeTypeTest(ExprLexer& lexer); + static Expr* createPathExpr(ExprLexer& lexer, txIParseContext* aContext); + static Expr* createUnionExpr(ExprLexer& lexer, txIParseContext* aContext); + + static MBool isFilterExprToken (Token* tok); + static MBool isLocationStepToken(Token* tok); + static MBool isNodeTypeToken (Token* tok); + + static short precedenceLevel (short tokenType); /** - * Using the given lexer, parses the tokens if they represent a predicate list - * If an error occurs a non-zero String pointer will be returned containing the - * error message. + * Resolve a QName, given the mContext parse context. + * Returns prefix and localName as well as namespace ID + **/ + static nsresult resolveQName(const String& aQName, txAtom*& aPrefix, + txIParseContext* aContext, + txAtom*& aLocalName, PRInt32& aNamespace); + + /** + * Using the given lexer, parses the tokens if they represent a + * predicate list + * If an error occurs a non-zero String pointer will be returned + * containing the error message. * @param predicateList, the PredicateList to add predicate expressions to * @param lexer the ExprLexer to use for parsing tokens * @return 0 if successful, or a String pointer to the error message **/ - MBool parsePredicates(PredicateList* predicateList, ExprLexer& lexer); - MBool parseParameters(FunctionCall* fnCall, ExprLexer& lexer); - + static MBool parsePredicates(PredicateList* predicateList, + ExprLexer& lexer, txIParseContext* aContext); + static MBool parseParameters(FunctionCall* fnCall, + ExprLexer& lexer, txIParseContext* aContext); }; //-- ExprParser diff --git a/content/xslt/src/xpath/txFilterExpr.cpp b/content/xslt/src/xpath/txFilterExpr.cpp index 0be6684cd210..3c56737e4725 100644 --- a/content/xslt/src/xpath/txFilterExpr.cpp +++ b/content/xslt/src/xpath/txFilterExpr.cpp @@ -26,6 +26,7 @@ */ #include "Expr.h" +#include "txIXPathContext.h" //-- Implementation of FilterExpr --/ @@ -56,24 +57,24 @@ FilterExpr::~FilterExpr() { * @return the result of the evaluation * @see Expr **/ -ExprResult* FilterExpr::evaluate(Node* context, ContextState* cs) { - - if (!context || !expr) +ExprResult* FilterExpr::evaluate(txIEvalContext* aContext) +{ + if (!aContext || !expr) return new NodeSet; - ExprResult* exprResult = expr->evaluate(context, cs); + ExprResult* exprResult = expr->evaluate(aContext); if (!exprResult) return 0; if (exprResult->getResultType() == ExprResult::NODESET) { // Result is a nodeset, filter it. - evaluatePredicates((NodeSet*)exprResult, cs); + evaluatePredicates((NodeSet*)exprResult, aContext); } else if(!isEmpty()) { // We can't filter a non-nodeset String err("Expecting nodeset as result of: "); expr->toString(err); - cs->recieveError(err); + aContext->receiveError(err, NS_ERROR_XPATH_EVAL_FAILED); delete exprResult; return new NodeSet; } @@ -81,40 +82,6 @@ ExprResult* FilterExpr::evaluate(Node* context, ContextState* cs) { return exprResult; } //-- evaluate -/** - * Returns the default priority of this Pattern based on the given Node, - * context Node, and ContextState. -**/ -double FilterExpr::getDefaultPriority(Node* node, Node* context, ContextState* cs) { - NS_ASSERTION(0, "FilterExpr is not allowed in Patterns"); - - if (isEmpty()) - return expr->getDefaultPriority(node, context, cs); - return 0.5; -} //-- getDefaultPriority - -/** - * Determines whether this Expr matches the given node within - * the given context -**/ -MBool FilterExpr::matches(Node* node, Node* context, ContextState* cs) { - - if (!expr) - return MB_FALSE; - - ExprResult* exprResult = evaluate(node, cs); - if (!exprResult) - return MB_FALSE; - - MBool result = MB_FALSE; - if(exprResult->getResultType() == ExprResult::NODESET) - result = ((NodeSet*)exprResult)->contains(node); - - delete exprResult; - return result; - -} //-- matches - /** * Creates a String representation of this Expr * @param str the destination String to append to diff --git a/content/xslt/src/xpath/txForwardContext.cpp b/content/xslt/src/xpath/txForwardContext.cpp new file mode 100644 index 000000000000..ac0131ab5f97 --- /dev/null +++ b/content/xslt/src/xpath/txForwardContext.cpp @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TransforMiiX XSLT Processor. + * + * The Initial Developer of the Original Code is + * Axel Hecht. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "txForwardContext.h" + +Node* txForwardContext::getContextNode() +{ + return mContext; +} + +PRUint32 txForwardContext::size() +{ + return (PRUint32)mContextSet->size(); +} + +PRUint32 txForwardContext::position() +{ + int pos = mContextSet->indexOf(mContext); + NS_ASSERTION(pos >= 0, "Context is not member of context node list."); + return (PRUint32)(pos+1); +} + +nsresult txForwardContext::getVariable(PRInt32 aNamespace, txAtom* aLName, + ExprResult*& aResult) +{ + NS_ASSERTION(mInner, "mInner is null!!!"); + return mInner->getVariable(aNamespace, aLName, aResult); +} + +MBool txForwardContext::isStripSpaceAllowed(Node* aNode) +{ + NS_ASSERTION(mInner, "mInner is null!!!"); + return mInner->isStripSpaceAllowed(aNode); +} + +void txForwardContext::receiveError(const String& aMsg, nsresult aRes) +{ + NS_ASSERTION(mInner, "mInner is null!!!"); +#ifdef DEBUG + String error("forwarded error: "); + error.append(aMsg); + mInner->receiveError(error, aRes); +#else + mInner->receiveError(aMsg, aRes); +#endif +} diff --git a/content/xslt/src/xpath/txForwardContext.h b/content/xslt/src/xpath/txForwardContext.h new file mode 100644 index 000000000000..41ecb67b0c35 --- /dev/null +++ b/content/xslt/src/xpath/txForwardContext.h @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TransforMiiX XSLT Processor. + * + * The Initial Developer of the Original Code is + * Axel Hecht. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __TX_XPATH_CONTEXT +#define __TX_XPATH_CONTEXT + +#include "txIXPathContext.h" + +class txForwardContext : public txIEvalContext +{ +public: + txForwardContext(txIMatchContext* aContext, Node* aContextNode, + NodeSet* aContextNodeSet) : mContext(aContextNode), + mContextSet(aContextNodeSet), + mInner(aContext) + {} + ~txForwardContext() + {} + + TX_DECL_EVAL_CONTEXT; + +private: + Node* mContext; + NodeSet* mContextSet; + txIMatchContext* mInner; +}; + +#endif // __TX_XPATH_CONTEXT diff --git a/content/xslt/src/xpath/txFunctionCall.cpp b/content/xslt/src/xpath/txFunctionCall.cpp index 5decbc12b88a..e6c9f0a8b682 100644 --- a/content/xslt/src/xpath/txFunctionCall.cpp +++ b/content/xslt/src/xpath/txFunctionCall.cpp @@ -24,6 +24,7 @@ */ #include "Expr.h" +#include "txIXPathContext.h" /** * This class represents a FunctionCall as defined by the XSL Working Draft @@ -77,50 +78,22 @@ FunctionCall::~FunctionCall() * Adds the given parameter to this FunctionCall's parameter list * @param expr the Expr to add to this FunctionCall's parameter list **/ -void FunctionCall::addParam(Expr* expr) +nsresult FunctionCall::addParam(Expr* aExpr) { - if (expr) - params.add(expr); + if (aExpr) + params.add(aExpr); + return NS_OK; } //-- addParam -/** - * Returns the default priority of this Expr based on the given Node, - * context Node, and ContextState. -**/ -double FunctionCall::getDefaultPriority(Node* node, - Node* context, - ContextState* cs) -{ - return 0.5; -} //-- getDefaultPriority - -/** - * Determines whether this Expr matches the given node within - * the given context -**/ -MBool FunctionCall::matches(Node* node, Node* context, ContextState* cs) -{ - MBool result = MB_FALSE; - ExprResult* exprResult = evaluate(node, cs); - if (exprResult->getResultType() == ExprResult::NODESET) { - NodeSet* nodes = (NodeSet*)exprResult; - result = (nodes->contains(node)); - } - delete exprResult; - return result; -} //-- matches - /* * Evaluates the given Expression and converts its result to a String. * The value is appended to the given destination String */ -void FunctionCall::evaluateToString(Expr* aExpr, - Node* aContext, - ContextState* aCs, +void FunctionCall::evaluateToString(Expr* aExpr, txIEvalContext* aContext, String& aDest) { NS_ASSERTION(aExpr, "missing expression"); - ExprResult* exprResult = aExpr->evaluate(aContext, aCs); + ExprResult* exprResult = aExpr->evaluate(aContext); if (!exprResult) return; @@ -131,12 +104,10 @@ void FunctionCall::evaluateToString(Expr* aExpr, /* * Evaluates the given Expression and converts its result to a number. */ -double FunctionCall::evaluateToNumber(Expr* aExpr, - Node* aContext, - ContextState* aCs) +double FunctionCall::evaluateToNumber(Expr* aExpr, txIEvalContext* aContext) { NS_ASSERTION(aExpr, "missing expression"); - ExprResult* exprResult = aExpr->evaluate(aContext, aCs); + ExprResult* exprResult = aExpr->evaluate(aContext); if (!exprResult) return Double::NaN; @@ -148,12 +119,10 @@ double FunctionCall::evaluateToNumber(Expr* aExpr, /* * Evaluates the given Expression and converts its result to a boolean. */ -MBool FunctionCall::evaluateToBoolean(Expr* aExpr, - Node* aContext, - ContextState* aCs) +MBool FunctionCall::evaluateToBoolean(Expr* aExpr, txIEvalContext* aContext) { NS_ASSERTION(aExpr, "missing expression"); - ExprResult* exprResult = aExpr->evaluate(aContext, aCs); + ExprResult* exprResult = aExpr->evaluate(aContext); if (!exprResult) return MB_FALSE; @@ -166,18 +135,16 @@ MBool FunctionCall::evaluateToBoolean(Expr* aExpr, * Evaluates the given Expression and converts its result to a NodeSet. * If the result is not a NodeSet NULL is returned. */ -NodeSet* FunctionCall::evaluateToNodeSet(Expr* aExpr, - Node* aContext, - ContextState* aCs) +NodeSet* FunctionCall::evaluateToNodeSet(Expr* aExpr, txIEvalContext* aContext) { NS_ASSERTION(aExpr, "Missing expression to evaluate"); - ExprResult* exprResult = aExpr->evaluate(aContext, aCs); + ExprResult* exprResult = aExpr->evaluate(aContext); if (!exprResult) return 0; if (exprResult->getResultType() != ExprResult::NODESET) { String err("NodeSet expected as argument"); - aCs->recieveError(err); + aContext->receiveError(err, NS_ERROR_XPATH_INVALID_ARG); delete exprResult; return 0; } @@ -190,13 +157,13 @@ NodeSet* FunctionCall::evaluateToNodeSet(Expr* aExpr, **/ MBool FunctionCall::requireParams (int paramCountMin, int paramCountMax, - ContextState* cs) + txIEvalContext* aContext) { int argc = params.getLength(); if ((argc < paramCountMin) || (argc > paramCountMax)) { String err(INVALID_PARAM_COUNT); toString(err); - cs->recieveError(err); + aContext->receiveError(err, NS_ERROR_XPATH_INVALID_ARG); return MB_FALSE; } return MB_TRUE; @@ -205,13 +172,13 @@ MBool FunctionCall::requireParams (int paramCountMin, /** * Called to check number of parameters **/ -MBool FunctionCall::requireParams(int paramCountMin, ContextState* cs) +MBool FunctionCall::requireParams(int paramCountMin, txIEvalContext* aContext) { int argc = params.getLength(); if (argc < paramCountMin) { String err(INVALID_PARAM_COUNT); toString(err); - cs->recieveError(err); + aContext->receiveError(err, NS_ERROR_XPATH_INVALID_ARG); return MB_FALSE; } return MB_TRUE; diff --git a/content/xslt/src/xpath/txFunctionLib.h b/content/xslt/src/xpath/txFunctionLib.h index 64611b82d458..580863ee0eca 100644 --- a/content/xslt/src/xpath/txFunctionLib.h +++ b/content/xslt/src/xpath/txFunctionLib.h @@ -125,14 +125,7 @@ public: **/ BooleanFunctionCall(BooleanFunctions aType); - /** - * Evaluates this Expr based on the given context node and processor state - * @param context the context node for evaluation of this Expr - * @param ps the ContextState containing the stack information needed - * for evaluation - * @return the result of the evaluation - **/ - ExprResult* evaluate(Node* aContext, ContextState* aCs); + TX_DECL_EVALUATE; private: BooleanFunctions mType; @@ -148,14 +141,7 @@ public: ErrorFunctionCall(); ErrorFunctionCall(const String& errorMsg); - /** - * Evaluates this Expr based on the given context node and processor state - * @param context the context node for evaluation of this Expr - * @param ps the ContextState containing the stack information needed - * for evaluation - * @return the result of the evaluation - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); + TX_DECL_EVALUATE; void setErrorMessage(String& errorMsg); @@ -165,89 +151,6 @@ private: }; //-- ErrorFunctionCall - -/** - * Used for extension functions -**/ -class ExtensionFunctionCall : public FunctionCall { - -public: - - static const String UNDEFINED_FUNCTION; - - /** - * Creates a new ExtensionFunctionCall with the given function name - * @param name the name of the extension function - **/ - ExtensionFunctionCall(const String& name); - - /** - * Destructor for extension function call - **/ - virtual ~ExtensionFunctionCall(); - - /** - * Evaluates this Expr based on the given context node and processor state - * @param context the context node for evaluation of this Expr - * @param ps the ContextState containing the stack information needed - * for evaluation - * @return the result of the evaluation - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - -private: - - String fname; - FunctionCall* fnCall; - -}; - -/** - * This class is used by ExtensionFunctionCall, to prevent deletion - * of the parameter expressions, by the resolved function call. The implementation - * for this class is in ExtensionFunctionCall.cpp -**/ -class ExprWrapper : public Expr { - -public: - - /** - * Creates a new ExprWrapper for the given Expr - **/ - ExprWrapper(Expr* expr); - - /** - * Destructor for ExprWrapper - **/ - virtual ~ExprWrapper(); - - /** - * Evaluates this Expr based on the given context node and processor state - * @param context the context node for evaluation of this Expr - * @param ps the ContextState containing the stack information needed - * for evaluation - * @return the result of the evaluation - **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); - - /** - * Returns the String representation of this Expr. - * @param dest the String to use when creating the String - * representation. The String representation will be appended to - * any data in the destination String, to allow cascading calls to - * other #toString() methods for Expressions. - * @return the String representation of this Expr. - **/ - virtual void toString(String& str); - -private: - - Expr* expr; - -}; //-- ExprWrapper - - - /* * A representation of the XPath NodeSet funtions */ @@ -270,14 +173,7 @@ public: */ NodeSetFunctionCall(NodeSetFunctions aType); - /* - * Evaluates this Expr based on the given context node and processor state - * @param context the context node for evaluation of this Expr - * @param ps the ContextState containing the stack information needed - * for evaluation - * @return the result of the evaluation - */ - ExprResult* evaluate(Node* aContext, ContextState* aCs); + TX_DECL_EVALUATE; private: NodeSetFunctions mType; @@ -309,14 +205,7 @@ public: **/ StringFunctionCall(StringFunctions aType); - /** - * Evaluates this Expr based on the given context node and processor state - * @param context the context node for evaluation of this Expr - * @param ps the ContextState containing the stack information needed - * for evaluation - * @return the result of the evaluation - **/ - ExprResult* evaluate(Node* aContext, ContextState* aCs); + TX_DECL_EVALUATE; private: StringFunctions mType; @@ -343,14 +232,7 @@ public: */ NumberFunctionCall(NumberFunctions aType); - /* - * Evaluates this Expr based on the given context node and processor state - * @param context the context node for evaluation of this Expr - * @param ps the ContextState containing the stack information needed - * for evaluation - * @return the result of the evaluation - */ - ExprResult* evaluate(Node* aContext, ContextState* aCs); + TX_DECL_EVALUATE; private: NumberFunctions mType; diff --git a/content/xslt/src/xpath/txIXPathContext.h b/content/xslt/src/xpath/txIXPathContext.h new file mode 100644 index 000000000000..09f0a833b103 --- /dev/null +++ b/content/xslt/src/xpath/txIXPathContext.h @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TransforMiiX XSLT Processor. + * + * The Initial Developer of the Original Code is + * Axel Hecht. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __TX_I_XPATH_CONTEXT +#define __TX_I_XPATH_CONTEXT + +#include "Expr.h" +#include "txError.h" + +/* + * txIParseContext + * + * This interface describes the context needed to create + * XPath Expressions and XSLT Patters. + * (not completely though. key() requires the ProcessorState, which is + * not part of this interface.) + */ + +class txIParseContext +{ +public: + virtual ~txIParseContext() + { + } + + /* + * Return a namespaceID for a given prefix. + */ + virtual nsresult resolveNamespacePrefix(txAtom* aPrefix, PRInt32& aID) = 0; + + /* + * Create a FunctionCall, needed for extension function calls and + * XSLT. XPath function calls are resolved by the Parser. + */ + virtual nsresult resolveFunctionCall(txAtom* aName, PRInt32 aID, + FunctionCall*& aFunction) = 0; + + /* + * Callback to be used by the Parser if errors are detected. + */ + virtual void receiveError(const String& aMsg, nsresult aRes) = 0; +}; + +/* + * txIMatchContext + * + * Interface used for matching XSLT Patters. + * This is the part of txIEvalContext (see below), that is independent + * of the context node when evaluating a XPath expression, too. + * When evaluating a XPath expression, |txIMatchContext|s are used + * to transport the information from Step to Step. + */ +class txIMatchContext +{ +public: + virtual ~txIMatchContext() + { + } + + /* + * Return the ExprResult associated with the variable with the + * given namespace and local name. + */ + virtual nsresult getVariable(PRInt32 aNamespace, txAtom* aLName, + ExprResult*& aResult) = 0; + + /* + * Is whitespace stripping allowed for the given node? + * See http://www.w3.org/TR/xslt#strip + */ + virtual MBool isStripSpaceAllowed(Node* aNode) = 0; + + /* + * Callback to be used by the expression/pattern if errors are detected. + */ + virtual void receiveError(const String& aMsg, nsresult aRes) = 0; +}; + +#define TX_DECL_MATCH_CONTEXT \ + nsresult getVariable(PRInt32 aNamespace, txAtom* aLName, \ + ExprResult*& aResult); \ + MBool isStripSpaceAllowed(Node* aNode); \ + void receiveError(const String& aMsg, nsresult aRes) + +class txIEvalContext : public txIMatchContext +{ +public: + virtual ~txIEvalContext() + { + } + + /* + * Get the context node. + */ + virtual Node* getContextNode() = 0; + + /* + * Get the size of the context node set. + */ + virtual PRUint32 size() = 0; + + /* + * Get the position of the context node in the context node set, + * starting with 1. + */ + virtual PRUint32 position() = 0; +}; + +#define TX_DECL_EVAL_CONTEXT \ + TX_DECL_MATCH_CONTEXT; \ + Node* getContextNode(); \ + PRUint32 size(); \ + PRUint32 position() + +#endif // __TX_I_XPATH_CONTEXT diff --git a/content/xslt/src/xpath/txLocationStep.cpp b/content/xslt/src/xpath/txLocationStep.cpp index 0e5511b1d95f..8f9afd09cceb 100644 --- a/content/xslt/src/xpath/txLocationStep.cpp +++ b/content/xslt/src/xpath/txLocationStep.cpp @@ -28,15 +28,17 @@ */ #include "Expr.h" +#include "txIXPathContext.h" /** * Creates a new LocationStep using the given NodeExpr and Axis Identifier * @param nodeExpr the NodeExpr to use when matching Nodes * @param axisIdentifier the Axis Identifier in which to search for nodes **/ -LocationStep::LocationStep(NodeExpr* nodeExpr, short axisIdentifier) : PredicateList() { - this->nodeExpr = nodeExpr; - this->axisIdentifier = axisIdentifier; +LocationStep::LocationStep(txNodeTest* aNodeTest, + LocationStepType aAxisIdentifier) + : mNodeTest(aNodeTest), mAxisIdentifier(aAxisIdentifier) +{ } //-- LocationStep /** @@ -45,7 +47,7 @@ LocationStep::LocationStep(NodeExpr* nodeExpr, short axisIdentifier) : Predicate * The NodeExpr will be deleted **/ LocationStep::~LocationStep() { - delete nodeExpr; + delete mNodeTest; } //-- ~LocationStep //-----------------------------/ @@ -60,23 +62,25 @@ LocationStep::~LocationStep() { * @return the result of the evaluation * @see Expr **/ -ExprResult* LocationStep::evaluate(Node* context, ContextState* cs) { +ExprResult* LocationStep::evaluate(txIEvalContext* aContext) +{ + NS_ASSERTION(aContext, "internal error"); NodeSet* nodes = new NodeSet(); - if (!context || !nodeExpr || !nodes) - return nodes; + if (!nodes) + return 0; MBool reverse = MB_FALSE; - Node* node = context; - switch (axisIdentifier) { + Node* node = aContext->getContextNode(); + switch (mAxisIdentifier) { case ANCESTOR_AXIS : - node = context->getXPathParent(); + node = node->getXPathParent(); //-- do not break here case ANCESTOR_OR_SELF_AXIS : reverse = MB_TRUE; while (node) { - if (nodeExpr->matches(node, context, cs)) { + if (mNodeTest->matches(node, aContext)) { nodes->append(node); } node = node->getXPathParent(); @@ -84,28 +88,28 @@ ExprResult* LocationStep::evaluate(Node* context, ContextState* cs) { break; case ATTRIBUTE_AXIS : { - NamedNodeMap* atts = context->getAttributes(); + NamedNodeMap* atts = node->getAttributes(); if (atts) { for (PRUint32 i = 0; i < atts->getLength(); i++) { Node* attr = atts->item(i); - if (nodeExpr->matches(attr, context, cs)) + if (mNodeTest->matches(attr, aContext)) nodes->append(attr); } } break; } case DESCENDANT_OR_SELF_AXIS : - if (nodeExpr->matches(context, context, cs)) - nodes->append(context); + if (mNodeTest->matches(node, aContext)) + nodes->append(node); //-- do not break here case DESCENDANT_AXIS : - fromDescendants(context, cs, nodes); + fromDescendants(node, aContext, nodes); break; case FOLLOWING_AXIS : { if ( node->getNodeType() == Node::ATTRIBUTE_NODE) { node = node->getXPathParent(); - fromDescendants(node, cs, nodes); + fromDescendants(node, aContext, nodes); } while (node && !node->getNextSibling()) { node = node->getXPathParent(); @@ -113,11 +117,11 @@ ExprResult* LocationStep::evaluate(Node* context, ContextState* cs) { while (node) { node = node->getNextSibling(); - if (nodeExpr->matches(node, context, cs)) + if (mNodeTest->matches(node, aContext)) nodes->append(node); if (node->hasChildNodes()) - fromDescendants(node, cs, nodes); + fromDescendants(node, aContext, nodes); while (node && !node->getNextSibling()) { node = node->getParentNode(); @@ -126,9 +130,9 @@ ExprResult* LocationStep::evaluate(Node* context, ContextState* cs) { break; } case FOLLOWING_SIBLING_AXIS : - node = context->getNextSibling(); + node = node->getNextSibling(); while (node) { - if (nodeExpr->matches(node, context, cs)) + if (mNodeTest->matches(node, aContext)) nodes->append(node); node = node->getNextSibling(); } @@ -141,8 +145,8 @@ ExprResult* LocationStep::evaluate(Node* context, ContextState* cs) { break; case PARENT_AXIS : { - Node* parent = context->getXPathParent(); - if ( nodeExpr->matches(parent, context, cs) ) + Node* parent = node->getXPathParent(); + if (mNodeTest->matches(parent, aContext)) nodes->append(parent); break; } @@ -155,9 +159,9 @@ ExprResult* LocationStep::evaluate(Node* context, ContextState* cs) { node = node->getPreviousSibling(); if (node->hasChildNodes()) - fromDescendantsRev(node, cs, nodes); + fromDescendantsRev(node, aContext, nodes); - if (nodeExpr->matches(node, context, cs)) + if (mNodeTest->matches(node, aContext)) nodes->append(node); while (node && !node->getPreviousSibling()) { @@ -167,56 +171,48 @@ ExprResult* LocationStep::evaluate(Node* context, ContextState* cs) { break; case PRECEDING_SIBLING_AXIS: reverse = MB_TRUE; - node = context->getPreviousSibling(); + node = node->getPreviousSibling(); while (node) { - if (nodeExpr->matches(node, context, cs)) + if (mNodeTest->matches(node, aContext)) nodes->append(node); node = node->getPreviousSibling(); } break; case SELF_AXIS : - if (nodeExpr->matches(context, context, cs)) - nodes->append(context); + if (mNodeTest->matches(node, aContext)) + nodes->append(node); break; default: //-- Children Axis { - Node* tmpNode = context->getFirstChild(); - while (tmpNode) { - if (nodeExpr->matches(tmpNode, context, cs)) - nodes->append(tmpNode); - tmpNode = tmpNode->getNextSibling(); + node = node->getFirstChild(); + while (node) { + if (mNodeTest->matches(node, aContext)) + nodes->append(node); + node = node->getNextSibling(); } break; } } //-- switch //-- apply predicates - evaluatePredicates(nodes, cs); + if (!isEmpty()) + evaluatePredicates(nodes, aContext); if (reverse) nodes->reverse(); return nodes; -} //-- evaluate +} -/** - * Returns the default priority of this Pattern based on the given Node, - * context Node, and ContextState. -**/ -double LocationStep::getDefaultPriority(Node* node, Node* context, ContextState* cs) { - if (isEmpty()) - return nodeExpr->getDefaultPriority(node, context, cs); - return 0.5; -} //-- getDefaultPriority +void LocationStep::fromDescendants(Node* node, txIMatchContext* cs, + NodeSet* nodes) +{ + if (!node) + return; - -void LocationStep::fromDescendants(Node* context, ContextState* cs, NodeSet* nodes) { - - if ( !context || !nodeExpr ) return; - - Node* child = context->getFirstChild(); + Node* child = node->getFirstChild(); while (child) { - if (nodeExpr->matches(child, context, cs)) + if (mNodeTest->matches(child, cs)) nodes->append(child); //-- check childs descendants if (child->hasChildNodes()) @@ -227,17 +223,19 @@ void LocationStep::fromDescendants(Node* context, ContextState* cs, NodeSet* nod } //-- fromDescendants -void LocationStep::fromDescendantsRev(Node* context, ContextState* cs, NodeSet* nodes) { +void LocationStep::fromDescendantsRev(Node* node, txIMatchContext* cs, + NodeSet* nodes) +{ + if (!node) + return; - if ( !context || !nodeExpr ) return; - - Node* child = context->getLastChild(); + Node* child = node->getLastChild(); while (child) { //-- check childs descendants if (child->hasChildNodes()) fromDescendantsRev(child, cs, nodes); - if (nodeExpr->matches(child, context, cs)) + if (mNodeTest->matches(child, cs)) nodes->append(child); child = child->getPreviousSibling(); @@ -245,40 +243,13 @@ void LocationStep::fromDescendantsRev(Node* context, ContextState* cs, NodeSet* } //-- fromDescendantsRev -/** - * Determines whether this Expr matches the given node within - * the given context -**/ -MBool LocationStep::matches(Node* node, Node* context, ContextState* cs) { - - if (!nodeExpr || !node) - return MB_FALSE; - - if (!nodeExpr->matches(node, context, cs)) - return MB_FALSE; - - MBool result = MB_TRUE; - if (!isEmpty()) { - NodeSet* nodes = (NodeSet*)evaluate(node->getXPathParent(),cs); - result = nodes->contains(node); - delete nodes; - } - else if (axisIdentifier == CHILD_AXIS ) { - if (!node->getParentNode()) - result = MB_FALSE; - } - - return result; - -} //-- matches - /** * Creates a String representation of this Expr * @param str the destination String to append to * @see Expr **/ void LocationStep::toString(String& str) { - switch (axisIdentifier) { + switch (mAxisIdentifier) { case ANCESTOR_AXIS : str.append("ancestor::"); break; @@ -318,8 +289,9 @@ void LocationStep::toString(String& str) { default: break; } - if ( nodeExpr ) nodeExpr->toString(str); - else str.append("null"); - PredicateList::toString(str); -} //-- toString + NS_ASSERTION(mNodeTest, "mNodeTest is null, that's verboten"); + mNodeTest->toString(str); + + PredicateList::toString(str); +} // toString diff --git a/content/xslt/src/xpath/txMultiplicativeExpr.cpp b/content/xslt/src/xpath/txMultiplicativeExpr.cpp index 4fcfd90c11b1..e5605f26cb52 100644 --- a/content/xslt/src/xpath/txMultiplicativeExpr.cpp +++ b/content/xslt/src/xpath/txMultiplicativeExpr.cpp @@ -59,21 +59,20 @@ MultiplicativeExpr::~MultiplicativeExpr() { * for evaluation * @return the result of the evaluation **/ -ExprResult* MultiplicativeExpr::evaluate(Node* context, ContextState* cs) { - - +ExprResult* MultiplicativeExpr::evaluate(txIEvalContext* aContext) +{ double rightDbl = Double::NaN; ExprResult* exprRes = 0; if ( rightExpr ) { - exprRes = rightExpr->evaluate(context, cs); + exprRes = rightExpr->evaluate(aContext); if ( exprRes ) rightDbl = exprRes->numberValue(); delete exprRes; } double leftDbl = Double::NaN; if ( leftExpr ) { - exprRes = leftExpr->evaluate(context, cs); + exprRes = leftExpr->evaluate(aContext); if ( exprRes ) leftDbl = exprRes->numberValue(); delete exprRes; } diff --git a/content/xslt/src/xpath/txNameTest.cpp b/content/xslt/src/xpath/txNameTest.cpp new file mode 100644 index 000000000000..e3d01f3d52f0 --- /dev/null +++ b/content/xslt/src/xpath/txNameTest.cpp @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is TransforMiiX XSLT processor. + * + * The Initial Developer of the Original Code is The MITRE Corporation. + * Portions created by MITRE are Copyright (C) 1999 The MITRE Corporation. + * + * Portions created by Keith Visco as a Non MITRE employee, + * (C) 1999 Keith Visco. All Rights Reserved. + * + * Contributor(s): + * Keith Visco, kvisco@ziplink.net + * -- original author. + * + */ + +#include "Expr.h" +#include "txAtoms.h" +#include "txIXPathContext.h" + +txNameTest::txNameTest(txAtom* aPrefix, txAtom* aLocalName, PRInt32 aNSID, + Node::NodeType aNodeType) + :mPrefix(aPrefix), mLocalName(aLocalName), mNamespace(aNSID), + mNodeType(aNodeType) +{ + if (aPrefix == txXMLAtoms::_empty) + mPrefix = 0; + NS_ASSERTION(aLocalName, "txNameTest without a local name?"); + TX_IF_ADDREF_ATOM(mPrefix); + TX_IF_ADDREF_ATOM(mLocalName); +} + +txNameTest::~txNameTest() +{ + TX_IF_RELEASE_ATOM(mPrefix); + TX_IF_RELEASE_ATOM(mLocalName); +} + +/* + * Determines whether this txNodeTest matches the given node + */ +MBool txNameTest::matches(Node* aNode, txIMatchContext* aContext) +{ + if (!aNode || aNode->getNodeType() != mNodeType) + return MB_FALSE; + + // Totally wild? + if (mLocalName == txXPathAtoms::_asterix && !mPrefix) + return MB_TRUE; + + // Compare namespaces + if (aNode->getNamespaceID() != mNamespace) + return MB_FALSE; + + // Name wild? + if (mLocalName == txXPathAtoms::_asterix) + return MB_TRUE; + + // Compare local-names + txAtom* localName; + aNode->getLocalName(&localName); + MBool result = localName == mLocalName; + TX_IF_RELEASE_ATOM(localName); + + return result; +} + +/* + * Returns the default priority of this txNodeTest + */ +double txNameTest::getDefaultPriority() +{ + if (mLocalName == txXPathAtoms::_asterix) { + if (!mPrefix) + return -0.5; + return -0.25; + } + return 0; +} + +/* + * Returns the String representation of this txNodeTest. + * @param aDest the String to use when creating the string representation. + * The string representation will be appended to the string. + */ +void txNameTest::toString(String& aDest) +{ + if (mPrefix) { + String prefix; + TX_GET_ATOM_STRING(mPrefix, prefix); + aDest.append(prefix); + aDest.append(':'); + } + String localName; + TX_GET_ATOM_STRING(mLocalName, localName); + aDest.append(localName); +} diff --git a/content/xslt/src/xpath/txNodeSetContext.cpp b/content/xslt/src/xpath/txNodeSetContext.cpp new file mode 100644 index 000000000000..50569e4fdd19 --- /dev/null +++ b/content/xslt/src/xpath/txNodeSetContext.cpp @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TransforMiiX XSLT Processor. + * + * The Initial Developer of the Original Code is + * Axel Hecht. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "txNodeSetContext.h" + +Node* txNodeSetContext::getContextNode() +{ + return mContextSet->get(mPosition - 1); +} + +PRUint32 txNodeSetContext::size() +{ + return (PRUint32)mContextSet->size(); +} + +PRUint32 txNodeSetContext::position() +{ + NS_ASSERTION(mPosition, "Should have called next() at least once"); + return mPosition; +} + +nsresult txNodeSetContext::getVariable(PRInt32 aNamespace, txAtom* aLName, + ExprResult*& aResult) +{ + NS_ASSERTION(mInner, "mInner is null!!!"); + return mInner->getVariable(aNamespace, aLName, aResult); +} + +MBool txNodeSetContext::isStripSpaceAllowed(Node* aNode) +{ + NS_ASSERTION(mInner, "mInner is null!!!"); + return mInner->isStripSpaceAllowed(aNode); +} + +void txNodeSetContext::receiveError(const String& aMsg, nsresult aRes) +{ + NS_ASSERTION(mInner, "mInner is null!!!"); +#ifdef DEBUG + String error("forwarded error: "); + error.append(aMsg); + mInner->receiveError(error, aRes); +#else + mInner->receiveError(aMsg, aRes); +#endif +} diff --git a/content/xslt/src/xpath/txNodeSetContext.h b/content/xslt/src/xpath/txNodeSetContext.h new file mode 100644 index 000000000000..d9c6212e0be7 --- /dev/null +++ b/content/xslt/src/xpath/txNodeSetContext.h @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TransforMiiX XSLT Processor. + * + * The Initial Developer of the Original Code is + * Axel Hecht. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __TX_XPATH_SET_CONTEXT +#define __TX_XPATH_SET_CONTEXT + +#include "txIXPathContext.h" + +class txNodeSetContext : public txIEvalContext +{ +public: + txNodeSetContext(NodeSet* aContextNodeSet, txIMatchContext* aContext) + : mContextSet(aContextNodeSet), mPosition(0), mInner(aContext) + { + } + ~txNodeSetContext() + { + } + + // Iteration over the given NodeSet + MBool hasNext() + { + return mPosition < size(); + } + void next() + { + NS_ASSERTION(mPosition < size(), "Out of bounds."); + mPosition++; + } + + TX_DECL_EVAL_CONTEXT; + +private: + NodeSet* mContextSet; + PRUint32 mPosition; + txIMatchContext* mInner; +}; + +#endif // __TX_XPATH_SET_CONTEXT diff --git a/content/xslt/src/xpath/txNodeSetFunctionCall.cpp b/content/xslt/src/xpath/txNodeSetFunctionCall.cpp index d786e76c4984..33d55660e32e 100644 --- a/content/xslt/src/xpath/txNodeSetFunctionCall.cpp +++ b/content/xslt/src/xpath/txNodeSetFunctionCall.cpp @@ -36,6 +36,7 @@ #include "XMLDOMUtils.h" #include "Tokenizer.h" #include "txAtom.h" +#include "txIXPathContext.h" /* * Creates a NodeSetFunctionCall of the given type @@ -75,16 +76,16 @@ NodeSetFunctionCall::NodeSetFunctionCall(NodeSetFunctions aType) * for evaluation * @return the result of the evaluation */ -ExprResult* NodeSetFunctionCall::evaluate(Node* aContext, ContextState* aCs) { +ExprResult* NodeSetFunctionCall::evaluate(txIEvalContext* aContext) { ListIterator iter(¶ms); switch (mType) { case COUNT: { - if (!requireParams(1, 1, aCs)) + if (!requireParams(1, 1, aContext)) return new StringResult("error"); NodeSet* nodes; - nodes = evaluateToNodeSet((Expr*)iter.next(), aContext, aCs); + nodes = evaluateToNodeSet((Expr*)iter.next(), aContext); if (!nodes) return new StringResult("error"); @@ -94,11 +95,11 @@ ExprResult* NodeSetFunctionCall::evaluate(Node* aContext, ContextState* aCs) { } case ID: { - if (!requireParams(1, 1, aCs)) + if (!requireParams(1, 1, aContext)) return new StringResult("error"); ExprResult* exprResult; - exprResult = ((Expr*)iter.next())->evaluate(aContext, aCs); + exprResult = ((Expr*)iter.next())->evaluate(aContext); if (!exprResult) return new StringResult("error"); @@ -108,11 +109,12 @@ ExprResult* NodeSetFunctionCall::evaluate(Node* aContext, ContextState* aCs) { return 0; } - Document* contextDoc; - if (aContext->getNodeType() == Node::DOCUMENT_NODE) - contextDoc = (Document*)aContext; + Document* contextDoc = 0; + Node* contextNode = aContext->getContextNode(); + if (contextNode->getNodeType() == Node::DOCUMENT_NODE) + contextDoc = (Document*)contextNode; else - contextDoc = aContext->getOwnerDocument(); + contextDoc = contextNode->getOwnerDocument(); if (exprResult->getResultType() == ExprResult::NODESET) { NodeSet* nodes = (NodeSet*)exprResult; @@ -123,7 +125,9 @@ ExprResult* NodeSetFunctionCall::evaluate(Node* aContext, ContextState* aCs) { txTokenizer tokenizer(idList); while (tokenizer.hasMoreTokens()) { tokenizer.nextToken(id); - resultSet->add(contextDoc->getElementById(id)); + Node* idNode = contextDoc->getElementById(id); + if (idNode) + resultSet->add(idNode); } } } @@ -133,7 +137,9 @@ ExprResult* NodeSetFunctionCall::evaluate(Node* aContext, ContextState* aCs) { txTokenizer tokenizer(idList); while (tokenizer.hasMoreTokens()) { tokenizer.nextToken(id); - resultSet->add(contextDoc->getElementById(id)); + Node* idNode = contextDoc->getElementById(id); + if (idNode) + resultSet->add(idNode); } } delete exprResult; @@ -142,30 +148,23 @@ ExprResult* NodeSetFunctionCall::evaluate(Node* aContext, ContextState* aCs) { } case LAST: { - if (!requireParams(0, 0, aCs)) + if (!requireParams(0, 0, aContext)) return new StringResult("error"); - NodeSet* contextNodeSet = (NodeSet*)aCs->getNodeSetStack()->peek(); - if (!contextNodeSet) { - String err("Internal error"); - aCs->recieveError(err); - return new StringResult("error"); - } - - return new NumberResult(contextNodeSet->size()); + return new NumberResult(aContext->size()); } case LOCAL_NAME: case NAME: case NAMESPACE_URI: { - if (!requireParams(0, 1, aCs)) + if (!requireParams(0, 1, aContext)) return new StringResult("error"); Node* node = 0; // Check for optional arg if (iter.hasNext()) { NodeSet* nodes; - nodes = evaluateToNodeSet((Expr*)iter.next(), aContext, aCs); + nodes = evaluateToNodeSet((Expr*)iter.next(), aContext); if (!nodes) return new StringResult("error"); @@ -177,7 +176,7 @@ ExprResult* NodeSetFunctionCall::evaluate(Node* aContext, ContextState* aCs) { delete nodes; } else { - node = aContext; + node = aContext->getContextNode(); } switch (mType) { @@ -219,21 +218,14 @@ ExprResult* NodeSetFunctionCall::evaluate(Node* aContext, ContextState* aCs) { } case POSITION: { - if (!requireParams(0, 0, aCs)) + if (!requireParams(0, 0, aContext)) return new StringResult("error"); - NodeSet* contextNodeSet = (NodeSet*)aCs->getNodeSetStack()->peek(); - if (!contextNodeSet) { - String err("Internal error"); - aCs->recieveError(err); - return new StringResult("error"); - } - - return new NumberResult(contextNodeSet->indexOf(aContext) + 1); + return new NumberResult(aContext->position()); } } String err("Internal error"); - aCs->recieveError(err); + aContext->receiveError(err, NS_ERROR_UNEXPECTED); return new StringResult("error"); } diff --git a/content/xslt/src/xpath/txNodeTypeTest.cpp b/content/xslt/src/xpath/txNodeTypeTest.cpp new file mode 100644 index 000000000000..64da786916b6 --- /dev/null +++ b/content/xslt/src/xpath/txNodeTypeTest.cpp @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is TransforMiiX XSLT processor. + * + * The Initial Developer of the Original Code is The MITRE Corporation. + * Portions created by MITRE are Copyright (C) 1999 The MITRE Corporation. + * + * Portions created by Keith Visco as a Non MITRE employee, + * (C) 1999 Keith Visco. All Rights Reserved. + * + * Contributor(s): + * Keith Visco, kvisco@ziplink.net + * -- original author. + * + */ + +#include "Expr.h" +#include "txAtom.h" +#include "txIXPathContext.h" + +/* + * Creates a new txNodeTypeTest of the given type + */ +txNodeTypeTest::txNodeTypeTest(NodeType aNodeType) + : mNodeType(aNodeType), mNodeName(0) +{ +} + +txNodeTypeTest::~txNodeTypeTest() +{ + TX_IF_RELEASE_ATOM(mNodeName); +} + +void txNodeTypeTest::setNodeName(const String& aName) +{ + mNodeName = TX_GET_ATOM(aName); +} + +/* + * Determines whether this txNodeTest matches the given node + */ +MBool txNodeTypeTest::matches(Node* aNode, txIMatchContext* aContext) +{ + if (!aNode) + return MB_FALSE; + + Node::NodeType type = (Node::NodeType)aNode->getNodeType(); + + switch (mNodeType) { + case COMMENT_TYPE: + return type == Node::COMMENT_NODE; + case TEXT_TYPE: + return (type == Node::TEXT_NODE || + type == Node::CDATA_SECTION_NODE) && + !aContext->isStripSpaceAllowed(aNode); + case PI_TYPE: + if (type == Node::PROCESSING_INSTRUCTION_NODE) { + txAtom* localName = 0; + MBool result; + result = !mNodeName || + (aNode->getLocalName(&localName) && + localName == mNodeName); + TX_IF_RELEASE_ATOM(localName); + return result; + } + return MB_FALSE; + case NODE_TYPE: + return ((type != Node::TEXT_NODE && + type != Node::CDATA_SECTION_NODE) || + !aContext->isStripSpaceAllowed(aNode)); + } + return MB_TRUE; +} + +/* + * Returns the default priority of this txNodeTest + */ +double txNodeTypeTest::getDefaultPriority() +{ + return mNodeName ? 0 : -0.5; +} + +/* + * Returns the String representation of this txNodeTest. + * @param aDest the String to use when creating the string representation. + * The string representation will be appended to the string. + */ +void txNodeTypeTest::toString(String& aDest) +{ + switch (mNodeType) { + case COMMENT_TYPE: + aDest.append("comment()"); + break; + case TEXT_TYPE: + aDest.append("text()"); + break; + case PI_TYPE: + aDest.append("processing-instruction("); + if (mNodeName) { + String str; + TX_GET_ATOM_STRING(mNodeName, str); + aDest.append('\''); + aDest.append(str); + aDest.append('\''); + } + aDest.append(')'); + break; + case NODE_TYPE: + aDest.append("node()"); + break; + } +} diff --git a/content/xslt/src/xpath/txNumberFunctionCall.cpp b/content/xslt/src/xpath/txNumberFunctionCall.cpp index 34274f74cf89..23ad0a8d3d7d 100644 --- a/content/xslt/src/xpath/txNumberFunctionCall.cpp +++ b/content/xslt/src/xpath/txNumberFunctionCall.cpp @@ -36,6 +36,7 @@ #include "FunctionLib.h" #include "XMLDOMUtils.h" #include +#include "txIXPathContext.h" /* * Creates a NumberFunctionCall of the given type @@ -68,23 +69,23 @@ NumberFunctionCall::NumberFunctionCall(NumberFunctions aType) { * for evaluation * @return the result of the evaluation */ -ExprResult* NumberFunctionCall::evaluate(Node* aContext, ContextState* aCs) +ExprResult* NumberFunctionCall::evaluate(txIEvalContext* aContext) { ListIterator iter(¶ms); if (mType == NUMBER) { - if (!requireParams(0, 1, aCs)) + if (!requireParams(0, 1, aContext)) return new StringResult("error"); } else { - if (!requireParams(1, 1, aCs)) + if (!requireParams(1, 1, aContext)) return new StringResult("error"); } switch (mType) { case CEILING: { - double dbl = evaluateToNumber((Expr*)iter.next(), aContext, aCs); + double dbl = evaluateToNumber((Expr*)iter.next(), aContext); if (Double::isNaN(dbl) || Double::isInfinite(dbl)) return new NumberResult(dbl); @@ -95,7 +96,7 @@ ExprResult* NumberFunctionCall::evaluate(Node* aContext, ContextState* aCs) } case FLOOR: { - double dbl = evaluateToNumber((Expr*)iter.next(), aContext, aCs); + double dbl = evaluateToNumber((Expr*)iter.next(), aContext); if (Double::isNaN(dbl) || Double::isInfinite(dbl) || (dbl == 0 && Double::isNeg(dbl))) @@ -105,7 +106,7 @@ ExprResult* NumberFunctionCall::evaluate(Node* aContext, ContextState* aCs) } case ROUND: { - double dbl = evaluateToNumber((Expr*)iter.next(), aContext, aCs); + double dbl = evaluateToNumber((Expr*)iter.next(), aContext); if (Double::isNaN(dbl) || Double::isInfinite(dbl)) return new NumberResult(dbl); @@ -117,7 +118,7 @@ ExprResult* NumberFunctionCall::evaluate(Node* aContext, ContextState* aCs) case SUM: { NodeSet* nodes; - nodes = evaluateToNodeSet((Expr*)iter.next(), aContext, aCs); + nodes = evaluateToNodeSet((Expr*)iter.next(), aContext); if (!nodes) return new StringResult("error"); @@ -137,16 +138,16 @@ ExprResult* NumberFunctionCall::evaluate(Node* aContext, ContextState* aCs) { if (iter.hasNext()) { return new NumberResult( - evaluateToNumber((Expr*)iter.next(), aContext, aCs)); + evaluateToNumber((Expr*)iter.next(), aContext)); } String resultStr; - XMLDOMUtils::getNodeValue(aContext, resultStr); + XMLDOMUtils::getNodeValue(aContext->getContextNode(), resultStr); return new NumberResult(Double::toDouble(resultStr)); } } String err("Internal error"); - aCs->recieveError(err); + aContext->receiveError(err, NS_ERROR_UNEXPECTED); return new StringResult("error"); } diff --git a/content/xslt/src/xpath/txPathExpr.cpp b/content/xslt/src/xpath/txPathExpr.cpp index 02ad5dbdac2f..350fc6805e07 100644 --- a/content/xslt/src/xpath/txPathExpr.cpp +++ b/content/xslt/src/xpath/txPathExpr.cpp @@ -33,11 +33,17 @@ #include "Expr.h" #include "XMLUtils.h" +#include "txNodeSetContext.h" +#include "txSingleNodeContext.h" //------------/ //- PathExpr -/ //------------/ +const String PathExpr::RTF_INVALID_OP = + "Result tree fragments don't allow location steps"; +const String PathExpr::NODESET_EXPECTED = + "Filter expression must evaluate to a NodeSet"; /** * Creates a new PathExpr @@ -94,12 +100,14 @@ void PathExpr::addExpr(Expr* expr, PathOperator pathOp) * for evaluation * @return the result of the evaluation **/ -ExprResult* PathExpr::evaluate(Node* context, ContextState* cs) +ExprResult* PathExpr::evaluate(txIEvalContext* aContext) { - if (!context || !expressions.getLength()) + if (!aContext || (expressions.getLength() == 0)) { + NS_ASSERTION(0, "internal error"); return new StringResult("error"); + } - NodeSet* nodes = new NodeSet(context); + NodeSet* nodes = new NodeSet(aContext->getContextNode()); if (!nodes) { // XXX ErrorReport: out of memory NS_ASSERTION(0, "out of memory"); @@ -111,16 +119,18 @@ ExprResult* PathExpr::evaluate(Node* context, ContextState* cs) while ((pxi = (PathExprItem*)iter.next())) { NodeSet* tmpNodes = 0; - for (int i = 0; i < nodes->size(); i++) { - Node* node = nodes->get(i); + txNodeSetContext eContext(nodes, aContext); + while (eContext.hasNext()) { + eContext.next(); + Node* node = eContext.getContextNode(); NodeSet* resNodes; if (pxi->pathOp == DESCENDANT_OP) { resNodes = new NodeSet; - evalDescendants(pxi->expr, node, cs, resNodes); + evalDescendants(pxi->expr, node, &eContext, resNodes); } else { - ExprResult *res = pxi->expr->evaluate(node, cs); + ExprResult *res = pxi->expr->evaluate(&eContext); if (!res || (res->getResultType() != ExprResult::NODESET)) { //XXX ErrorReport: report nonnodeset error delete res; @@ -147,12 +157,13 @@ ExprResult* PathExpr::evaluate(Node* context, ContextState* cs) /** * Selects from the descendants of the context node * all nodes that match the Expr - * -- this will be moving to a Utility class **/ -void PathExpr::evalDescendants (Expr* expr, Node* context, - ContextState* cs, NodeSet* resNodes) +void PathExpr::evalDescendants (Expr* aStep, Node* aNode, + txIMatchContext* aContext, + NodeSet* resNodes) { - ExprResult *res = expr->evaluate(context, cs); + txSingleNodeContext eContext(aNode, aContext); + ExprResult *res = aStep->evaluate(&eContext); if (!res || (res->getResultType() != ExprResult::NODESET)) { //XXX ErrorReport: report nonnodeset error } @@ -161,107 +172,19 @@ void PathExpr::evalDescendants (Expr* expr, Node* context, } delete res; - MBool filterWS = cs->isStripSpaceAllowed(context); + MBool filterWS = aContext->isStripSpaceAllowed(aNode); - Node* child = context->getFirstChild(); + Node* child = aNode->getFirstChild(); while (child) { if (!(filterWS && (child->getNodeType() == Node::TEXT_NODE || child->getNodeType() == Node::CDATA_SECTION_NODE) && XMLUtils::shouldStripTextnode(child->getNodeValue()))) - evalDescendants(expr, child, cs, resNodes); + evalDescendants(aStep, child, aContext, resNodes); child = child->getNextSibling(); } } //-- evalDescendants -/** - * Returns the default priority of this Pattern based on the given Node, - * context Node, and ContextState. -**/ -double PathExpr::getDefaultPriority(Node* node, Node* context, - ContextState* cs) -{ - int size = expressions.getLength(); - if (size > 1) - return 0.5; - - return ((PathExprItem*)expressions.get(0))-> - expr->getDefaultPriority(node, context, cs); -} //-- getDefaultPriority - -/** - * Determines whether this Expr matches the given node within - * the given context -**/ -MBool PathExpr::matches(Node* node, Node* context, ContextState* cs) -{ - /* - * The idea is to split up a path into blocks separated by descendant - * operators. For example "foo/bar//baz/bop//ying/yang" is split up into - * three blocks. The "ying/yang" block is handled by the first while-loop - * and the "foo/bar" and "baz/bop" blocks are handled by the second - * while-loop. - * A block is considered matched when we find a list of ancestors that - * match the block. If there are more than one list of ancestors that - * match a block we only need to find the one furthermost down in the - * tree. - */ - - if (!node || (expressions.getLength() == 0)) - return MB_FALSE; - - ListIterator iter(&expressions); - iter.resetToEnd(); - - PathExprItem* pxi; - PathOperator pathOp = RELATIVE_OP; - - while (pathOp == RELATIVE_OP) { - - pxi = (PathExprItem*)iter.previous(); - if (!pxi) - return MB_TRUE; // We've stepped through the entire list - - if (!node || !pxi->expr->matches(node, 0, cs)) - return MB_FALSE; - - node = node->getXPathParent(); - pathOp = pxi->pathOp; - } - - // We have at least one DESCENDANT_OP - - Node* blockStart = node; - ListIterator blockIter(iter); - - while ((pxi = (PathExprItem*)iter.previous())) { - - if (!node) - return MB_FALSE; // There are more steps in the current block - // then ancestors of the tested node - - if (!pxi->expr->matches(node, 0, cs)) { - // Didn't match. We restart at beginning of block using a new - // start node - iter = blockIter; - blockStart = blockStart->getXPathParent(); - node = blockStart; - } - else { - node = node->getXPathParent(); - if (pxi->pathOp == DESCENDANT_OP) { - // We've matched an entire block. Set new start iter and start node - blockIter = iter; - blockStart = node; - } - } - } - - return MB_TRUE; - -} //-- matches - - /** * Returns the String representation of this Expr. * @param dest the String to use when creating the String diff --git a/content/xslt/src/xpath/txPredicateList.cpp b/content/xslt/src/xpath/txPredicateList.cpp index 689dd3c3a6ab..8fcfdb731475 100644 --- a/content/xslt/src/xpath/txPredicateList.cpp +++ b/content/xslt/src/xpath/txPredicateList.cpp @@ -24,6 +24,7 @@ */ #include "Expr.h" +#include "txNodeSetContext.h" /* * Represents an ordered list of Predicates, @@ -56,38 +57,39 @@ void PredicateList::add(Expr* expr) predicates.add(expr); } // add -void PredicateList::evaluatePredicates(NodeSet* nodes, ContextState* cs) +void PredicateList::evaluatePredicates(NodeSet* nodes, + txIMatchContext* aContext) { NS_ASSERTION(nodes, "called evaluatePredicates with NULL NodeSet"); if (!nodes) return; - cs->getNodeSetStack()->push(nodes); NodeSet newNodes; txListIterator iter(&predicates); - while (iter.hasNext()) { + while (iter.hasNext() && !nodes->isEmpty()) { Expr* expr = (Expr*)iter.next(); + txNodeSetContext predContext(nodes, aContext); /* * add nodes to newNodes that match the expression * or, if the result is a number, add the node with the right * position */ newNodes.clear(); - int nIdx; - for (nIdx = 0; nIdx < nodes->size(); nIdx++) { - Node* node = nodes->get(nIdx); - ExprResult* exprResult = expr->evaluate(node, cs); + while (predContext.hasNext()) { + predContext.next(); + ExprResult* exprResult = expr->evaluate(&predContext); if (!exprResult) break; switch(exprResult->getResultType()) { case ExprResult::NUMBER : // handle default, [position() == numberValue()] - if ((double)(nIdx+1) == exprResult->numberValue()) - newNodes.append(node); + if ((double)predContext.position() == + exprResult->numberValue()) + newNodes.append(predContext.getContextNode()); break; default: if (exprResult->booleanValue()) - newNodes.append(node); + newNodes.append(predContext.getContextNode()); break; } delete exprResult; @@ -96,7 +98,6 @@ void PredicateList::evaluatePredicates(NodeSet* nodes, ContextState* cs) nodes->clear(); nodes->append(&newNodes); } - cs->getNodeSetStack()->pop(); } /* diff --git a/content/xslt/src/xpath/txRelationalExpr.cpp b/content/xslt/src/xpath/txRelationalExpr.cpp index aac3473fb272..f3fdd5a8fcb1 100644 --- a/content/xslt/src/xpath/txRelationalExpr.cpp +++ b/content/xslt/src/xpath/txRelationalExpr.cpp @@ -204,16 +204,19 @@ MBool RelationalExpr::compareResults(ExprResult* left, ExprResult* right) { * for evaluation * @return the result of the evaluation **/ -ExprResult* RelationalExpr::evaluate(Node* context, ContextState* cs) { - +ExprResult* RelationalExpr::evaluate(txIEvalContext* aContext) +{ //-- get result of left expression ExprResult* lResult = 0; - if ( leftExpr ) lResult = leftExpr->evaluate(context, cs); - else return new BooleanResult(); + if (leftExpr) + lResult = leftExpr->evaluate(aContext); + else + return new BooleanResult(); //-- get result of right expr ExprResult* rResult = 0; - if ( rightExpr ) rResult = rightExpr->evaluate(context, cs); + if (rightExpr) + rResult = rightExpr->evaluate(aContext); else { delete lResult; return new BooleanResult(); diff --git a/content/xslt/src/xpath/txRootExpr.cpp b/content/xslt/src/xpath/txRootExpr.cpp index a7562f6c280d..948b0c65eacb 100644 --- a/content/xslt/src/xpath/txRootExpr.cpp +++ b/content/xslt/src/xpath/txRootExpr.cpp @@ -24,6 +24,7 @@ */ #include "Expr.h" +#include "txIXPathContext.h" /** * Creates a new RootExpr @@ -40,32 +41,19 @@ RootExpr::RootExpr(MBool aSerialize) { * for evaluation * @return the result of the evaluation **/ -ExprResult* RootExpr::evaluate(Node* context, ContextState* cs) +ExprResult* RootExpr::evaluate(txIEvalContext* aContext) { - if (!context) - return new StringResult("error"); + Node* context; + if (!aContext || !(context = aContext->getContextNode())) { + NS_ASSERTION(0, "internal error"); + return 0; + } if (context->getNodeType() != Node::DOCUMENT_NODE) return new NodeSet(context->getOwnerDocument()); return new NodeSet(context); } //-- evaluate -/** - * Returns the default priority of this Pattern based on the given Node, - * context Node, and ContextState. -**/ -double RootExpr::getDefaultPriority(Node* node, Node* context, ContextState* cs) { - return 0.5; -} //-- getDefaultPriority - -/** - * Determines whether this NodeExpr matches the given node within - * the given context -**/ -MBool RootExpr::matches(Node* node, Node* context, ContextState* cs) { - return node && (node->getNodeType() == Node::DOCUMENT_NODE); -} //-- matches - /** * Returns the String representation of this Expr. * @param dest the String to use when creating the String diff --git a/content/xslt/src/xpath/txSingleNodeContext.h b/content/xslt/src/xpath/txSingleNodeContext.h new file mode 100644 index 000000000000..bc6cab10c4b1 --- /dev/null +++ b/content/xslt/src/xpath/txSingleNodeContext.h @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TransforMiiX XSLT Processor. + * + * The Initial Developer of the Original Code is + * Axel Hecht. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __TX_XPATH_SINGLENODE_CONTEXT +#define __TX_XPATH_SINGLENODE_CONTEXT + +#include "txIXPathContext.h" + +class txSingleNodeContext : public txIEvalContext +{ +public: + txSingleNodeContext(Node* aContextNode, txIMatchContext* aContext) + : mNode(aContextNode), mInner(aContext) + { + NS_ASSERTION(aContextNode, "context node must be given"); + NS_ASSERTION(aContext, "txIMatchContext must be given"); + } + ~txSingleNodeContext() + {} + + nsresult getVariable(PRInt32 aNamespace, txAtom* aLName, + ExprResult*& aResult) + { + NS_ASSERTION(mInner, "mInner is null!!!"); + return mInner->getVariable(aNamespace, aLName, aResult); + } + + MBool isStripSpaceAllowed(Node* aNode) + { + NS_ASSERTION(mInner, "mInner is null!!!"); + return mInner->isStripSpaceAllowed(aNode); + } + + void receiveError(const String& aMsg, nsresult aRes) + { + NS_ASSERTION(mInner, "mInner is null!!!"); +#ifdef DEBUG + String error("forwarded error: "); + error.append(aMsg); + mInner->receiveError(error, aRes); +#else + mInner->receiveError(aMsg, aRes); +#endif + } + + Node* getContextNode() + { + return mNode; + } + + PRUint32 size() + { + return 1; + } + + PRUint32 position() + { + return 1; + } + +private: + Node* mNode; + txIMatchContext* mInner; +}; + +#endif // __TX_XPATH_SINGLENODE_CONTEXT diff --git a/content/xslt/src/xpath/txStringFunctionCall.cpp b/content/xslt/src/xpath/txStringFunctionCall.cpp index c68da321f8a1..190eaabe1717 100644 --- a/content/xslt/src/xpath/txStringFunctionCall.cpp +++ b/content/xslt/src/xpath/txStringFunctionCall.cpp @@ -31,6 +31,7 @@ #include "FunctionLib.h" #include "XMLDOMUtils.h" +#include "txIXPathContext.h" #include /** @@ -76,41 +77,42 @@ StringFunctionCall::StringFunctionCall(StringFunctions aType) : mType(aType) * for evaluation * @return the result of the evaluation **/ -ExprResult* StringFunctionCall::evaluate(Node* aContext, ContextState* aCs) +ExprResult* StringFunctionCall::evaluate(txIEvalContext* aContext) { ListIterator iter(¶ms); switch (mType) { case CONCAT: { - if (!requireParams(2, aCs)) + if (!requireParams(2, aContext)) return new StringResult("error"); String resultStr; while (iter.hasNext()) { - evaluateToString((Expr*)iter.next(), aContext, aCs, resultStr); + evaluateToString((Expr*)iter.next(), aContext, resultStr); } return new StringResult(resultStr); } case CONTAINS: { - if (!requireParams(2, 2, aCs)) + if (!requireParams(2, 2, aContext)) return new StringResult("error"); String arg1, arg2; - evaluateToString((Expr*)iter.next(), aContext, aCs, arg1); - evaluateToString((Expr*)iter.next(), aContext, aCs, arg2); + evaluateToString((Expr*)iter.next(), aContext, arg1); + evaluateToString((Expr*)iter.next(), aContext, arg2); return new BooleanResult(arg1.indexOf(arg2) >= 0); } case NORMALIZE_SPACE: { - if (!requireParams(0, 1, aCs)) + if (!requireParams(0, 1, aContext)) return new StringResult("error"); String resultStr; if (iter.hasNext()) - evaluateToString((Expr*)iter.next(), aContext, aCs, resultStr); + evaluateToString((Expr*)iter.next(), aContext, resultStr); else - XMLDOMUtils::getNodeValue(aContext, resultStr); + XMLDOMUtils::getNodeValue(aContext->getContextNode(), + resultStr); MBool addSpace = MB_FALSE; MBool first = MB_TRUE; @@ -136,35 +138,36 @@ ExprResult* StringFunctionCall::evaluate(Node* aContext, ContextState* aCs) } case STARTS_WITH: { - if (!requireParams(2, 2, aCs)) + if (!requireParams(2, 2, aContext)) return new StringResult("error"); String arg1, arg2; - evaluateToString((Expr*)iter.next(), aContext, aCs, arg1); - evaluateToString((Expr*)iter.next(), aContext, aCs, arg2); + evaluateToString((Expr*)iter.next(), aContext, arg1); + evaluateToString((Expr*)iter.next(), aContext, arg2); return new BooleanResult(arg1.indexOf(arg2) == 0); } case STRING_LENGTH: { - if (!requireParams(0, 1, aCs)) + if (!requireParams(0, 1, aContext)) return new StringResult("error"); String resultStr; if (iter.hasNext()) - evaluateToString((Expr*)iter.next(), aContext, aCs, resultStr); + evaluateToString((Expr*)iter.next(), aContext, resultStr); else - XMLDOMUtils::getNodeValue(aContext, resultStr); + XMLDOMUtils::getNodeValue(aContext->getContextNode(), + resultStr); return new NumberResult(resultStr.length()); } case SUBSTRING: { - if (!requireParams(2, 3, aCs)) + if (!requireParams(2, 3, aContext)) return new StringResult("error"); String src; double start, end; - evaluateToString((Expr*)iter.next(), aContext, aCs, src); - start = evaluateToNumber((Expr*)iter.next(), aContext, aCs); + evaluateToString((Expr*)iter.next(), aContext, src); + start = evaluateToNumber((Expr*)iter.next(), aContext); // check for NaN or +/-Inf if (Double::isNaN(start) || @@ -175,8 +178,7 @@ ExprResult* StringFunctionCall::evaluate(Node* aContext, ContextState* aCs) start = floor(start + 0.5) - 1; if (iter.hasNext()) { end = start + evaluateToNumber((Expr*)iter.next(), - aContext, - aCs); + aContext); if (Double::isNaN(end) || end < 0) return new StringResult(); @@ -201,12 +203,12 @@ ExprResult* StringFunctionCall::evaluate(Node* aContext, ContextState* aCs) } case SUBSTRING_AFTER: { - if (!requireParams(2, 2, aCs)) + if (!requireParams(2, 2, aContext)) return new StringResult("error"); String arg1, arg2; - evaluateToString((Expr*)iter.next(), aContext, aCs, arg1); - evaluateToString((Expr*)iter.next(), aContext, aCs, arg2); + evaluateToString((Expr*)iter.next(), aContext, arg1); + evaluateToString((Expr*)iter.next(), aContext, arg2); PRInt32 idx = arg1.indexOf(arg2); if (idx >= 0) { PRInt32 len = arg2.length(); @@ -217,12 +219,12 @@ ExprResult* StringFunctionCall::evaluate(Node* aContext, ContextState* aCs) } case SUBSTRING_BEFORE: { - if (!requireParams(2, 2, aCs)) + if (!requireParams(2, 2, aContext)) return new StringResult("error"); String arg1, arg2; - evaluateToString((Expr*)iter.next(), aContext, aCs, arg1); - evaluateToString((Expr*)iter.next(), aContext, aCs, arg2); + evaluateToString((Expr*)iter.next(), aContext, arg1); + evaluateToString((Expr*)iter.next(), aContext, arg2); PRInt32 idx = arg1.indexOf(arg2); if (idx >= 0) { arg2.clear(); @@ -233,17 +235,17 @@ ExprResult* StringFunctionCall::evaluate(Node* aContext, ContextState* aCs) } case TRANSLATE: { - if (!requireParams(3, 3, aCs)) + if (!requireParams(3, 3, aContext)) return new StringResult("error"); String src; - evaluateToString((Expr*)iter.next(), aContext, aCs, src); + evaluateToString((Expr*)iter.next(), aContext, src); if (src.isEmpty()) return new StringResult(); String oldChars, newChars, dest; - evaluateToString((Expr*)iter.next(), aContext, aCs, oldChars); - evaluateToString((Expr*)iter.next(), aContext, aCs, newChars); + evaluateToString((Expr*)iter.next(), aContext, oldChars); + evaluateToString((Expr*)iter.next(), aContext, newChars); PRInt32 i; for (i = 0; i < src.length(); i++) { PRInt32 idx = oldChars.indexOf(src.charAt(i)); @@ -259,19 +261,20 @@ ExprResult* StringFunctionCall::evaluate(Node* aContext, ContextState* aCs) } case STRING: { - if (!requireParams(0, 1, aCs)) + if (!requireParams(0, 1, aContext)) return new StringResult("error"); String resultStr; if (iter.hasNext()) - evaluateToString((Expr*)iter.next(), aContext, aCs, resultStr); + evaluateToString((Expr*)iter.next(), aContext, resultStr); else - XMLDOMUtils::getNodeValue(aContext, resultStr); + XMLDOMUtils::getNodeValue(aContext->getContextNode(), + resultStr); return new StringResult(resultStr); } } String err("Internal error"); - aCs->recieveError(err); + aContext->receiveError(err, NS_ERROR_UNEXPECTED); return new StringResult("error"); } diff --git a/content/xslt/src/xpath/txUnaryExpr.cpp b/content/xslt/src/xpath/txUnaryExpr.cpp index 4a9f37895153..fbc5ea928258 100644 --- a/content/xslt/src/xpath/txUnaryExpr.cpp +++ b/content/xslt/src/xpath/txUnaryExpr.cpp @@ -42,9 +42,9 @@ UnaryExpr::~UnaryExpr() * for evaluation. * @return the result of the evaluation. */ -ExprResult* UnaryExpr::evaluate(Node* context, ContextState* cs) +ExprResult* UnaryExpr::evaluate(txIEvalContext* aContext) { - ExprResult* exprRes = expr->evaluate(context, cs); + ExprResult* exprRes = expr->evaluate(aContext); double value = exprRes->numberValue(); delete exprRes; #ifdef HPUX diff --git a/content/xslt/src/xpath/txUnionExpr.cpp b/content/xslt/src/xpath/txUnionExpr.cpp index eae7a2849c14..2b13a8b4131e 100644 --- a/content/xslt/src/xpath/txUnionExpr.cpp +++ b/content/xslt/src/xpath/txUnionExpr.cpp @@ -69,21 +69,22 @@ void UnionExpr::addExpr(Expr* expr) { * for evaluation * @return the result of the evaluation **/ -ExprResult* UnionExpr::evaluate(Node* context, ContextState* cs) +ExprResult* UnionExpr::evaluate(txIEvalContext* aContext) { NodeSet* nodes = new NodeSet(); - if (!context || expressions.getLength() == 0 || !nodes) + if (!aContext || (expressions.getLength() == 0) || !nodes) return nodes; txListIterator iter(&expressions); while (iter.hasNext()) { Expr* expr = (Expr*)iter.next(); - ExprResult* exprResult = expr->evaluate(context, cs); + ExprResult* exprResult = expr->evaluate(aContext); if (!exprResult || exprResult->getResultType() != ExprResult::NODESET) { delete exprResult; + delete nodes; return new StringResult("error"); } nodes->add((NodeSet*)exprResult); @@ -93,45 +94,6 @@ ExprResult* UnionExpr::evaluate(Node* context, ContextState* cs) return nodes; } //-- evaluate -/** - * Returns the default priority of this Pattern based on the given Node, - * context Node, and ContextState. -**/ -double UnionExpr::getDefaultPriority(Node* node, Node* context, - ContextState* cs) -{ - //-- find highest priority - double priority = Double::NEGATIVE_INFINITY; - ListIterator iter(&expressions); - while (iter.hasNext()) { - Expr* expr = (Expr*)iter.next(); - double tmpPriority = expr->getDefaultPriority(node, context, cs); - if (tmpPriority > priority && expr->matches(node, context, cs)) - priority = tmpPriority; - } - return priority; -} //-- getDefaultPriority - -/** - * Determines whether this UnionExpr matches the given node within - * the given context -**/ -MBool UnionExpr::matches(Node* node, Node* context, ContextState* cs) { - - ListIterator* iter = expressions.iterator(); - - while (iter->hasNext()) { - Expr* expr = (Expr*)iter->next(); - if (expr->matches(node, context, cs)) { - delete iter; - return MB_TRUE; - } - } - delete iter; - return MB_FALSE; -} //-- matches - - /** * Returns the String representation of this Expr. * @param dest the String to use when creating the String diff --git a/content/xslt/src/xpath/txVariableRefExpr.cpp b/content/xslt/src/xpath/txVariableRefExpr.cpp index b48da2807b6d..292d5b1d1260 100644 --- a/content/xslt/src/xpath/txVariableRefExpr.cpp +++ b/content/xslt/src/xpath/txVariableRefExpr.cpp @@ -24,6 +24,8 @@ */ #include "Expr.h" +#include "txAtoms.h" +#include "txIXPathContext.h" //-------------------/ //- VariableRefExpr -/ @@ -32,9 +34,25 @@ /** * Creates a VariableRefExpr with the given variable name **/ -VariableRefExpr::VariableRefExpr(const String& name) { - this->name = name; -} //-- VariableRefExpr +VariableRefExpr::VariableRefExpr(txAtom* aPrefix, txAtom* aLocalName, + PRInt32 aNSID) + : mPrefix(aPrefix), mLocalName(aLocalName), mNamespace(aNSID) +{ + NS_ASSERTION(mLocalName, "VariableRefExpr without local name?"); + if (mPrefix == txXMLAtoms::_empty) + mPrefix = 0; + TX_IF_ADDREF_ATOM(mPrefix); + TX_IF_ADDREF_ATOM(mLocalName); +} + +/* + * Release the local name atom + */ +VariableRefExpr::~VariableRefExpr() +{ + TX_IF_RELEASE_ATOM(mPrefix); + TX_IF_RELEASE_ATOM(mLocalName); +} /** * Evaluates this Expr based on the given context node and processor state @@ -43,9 +61,14 @@ VariableRefExpr::VariableRefExpr(const String& name) { * for evaluation * @return the result of the evaluation **/ -ExprResult* VariableRefExpr::evaluate(Node* context, ContextState* cs) { - - ExprResult* exprResult = cs->getVariable(name); +ExprResult* VariableRefExpr::evaluate(txIEvalContext* aContext) +{ + ExprResult* exprResult = 0; + nsresult rv = aContext->getVariable(mNamespace, mLocalName, exprResult); + if (NS_FAILED(rv)) { + // XXX report error, undefined variable + return 0; + } //-- make copy to prevent deletetion //-- I know, I should add a #copy method to ExprResult, I will ExprResult* copyOfResult = 0; @@ -88,7 +111,16 @@ ExprResult* VariableRefExpr::evaluate(Node* context, ContextState* cs) { * other #toString() methods for Expressions. * @return the String representation of this Expr. **/ -void VariableRefExpr::toString(String& str) { - str.append('$'); - str.append(name); +void VariableRefExpr::toString(String& aDest) +{ + aDest.append('$'); + if (mPrefix) { + String prefix; + TX_GET_ATOM_STRING(mPrefix, prefix); + aDest.append(prefix); + aDest.append(':'); + } + String lname; + TX_GET_ATOM_STRING(mLocalName, lname); + aDest.append(lname); } //-- toString diff --git a/content/xslt/src/xslt/Makefile.in b/content/xslt/src/xslt/Makefile.in index 8dfec90a8122..8694f050c511 100644 --- a/content/xslt/src/xslt/Makefile.in +++ b/content/xslt/src/xslt/Makefile.in @@ -54,6 +54,8 @@ CPPSRCS = Names.cpp \ txRtfHandler.cpp \ txTextHandler.cpp \ VariableBinding.cpp \ + txXSLTPatterns.cpp \ + txPatternParser.cpp \ XSLTProcessor.cpp ifdef TX_EXE diff --git a/content/xslt/src/xslt/txCurrentFunctionCall.cpp b/content/xslt/src/xslt/txCurrentFunctionCall.cpp index cd9adf749370..04de602ef6b6 100644 --- a/content/xslt/src/xslt/txCurrentFunctionCall.cpp +++ b/content/xslt/src/xslt/txCurrentFunctionCall.cpp @@ -8,22 +8,19 @@ /** * Creates a new current function call **/ -CurrentFunctionCall::CurrentFunctionCall(ProcessorState* ps) : - FunctionCall(CURRENT_FN) +CurrentFunctionCall::CurrentFunctionCall(ProcessorState* aPs) + : FunctionCall(CURRENT_FN), mPs(aPs) { - this->processorState = ps; } -/** - * Evaluates this Expr based on the given context node and processor state - * @param context the context node for evaluation of this Expr - * @param cs the ContextState containing the stack information needed - * for evaluation - * @return the result of the evaluation - * @see FunctionCall.h -**/ -ExprResult* CurrentFunctionCall::evaluate(Node* context, ContextState* cs) +/* + * Evaluates this Expr + * + * @return NodeSet containing the context node used for the complete + * Expr or Pattern. + */ +ExprResult* CurrentFunctionCall::evaluate(txIEvalContext* aContext) { - return new NodeSet(processorState->getCurrentNode()); + return new NodeSet(mPs->getEvalContext()->getContextNode()); } diff --git a/content/xslt/src/xslt/txDocumentFunctionCall.cpp b/content/xslt/src/xslt/txDocumentFunctionCall.cpp index e808d6c283d6..28b3487e322e 100644 --- a/content/xslt/src/xslt/txDocumentFunctionCall.cpp +++ b/content/xslt/src/xslt/txDocumentFunctionCall.cpp @@ -39,6 +39,7 @@ #include "XSLTFunctions.h" #include "XMLDOMUtils.h" #include "Names.h" +#include "txIXPathContext.h" /* * Creates a new DocumentFunctionCall. @@ -56,19 +57,17 @@ DocumentFunctionCall::DocumentFunctionCall(ProcessorState* aPs, * NOTE: the implementation is incomplete since it does not make use of the * second argument (base URI) * @param context the context node for evaluation of this Expr - * @param ps the ContextState containing the stack information needed - * for evaluation * @return the result of the evaluation */ -ExprResult* DocumentFunctionCall::evaluate(Node* context, ContextState* cs) +ExprResult* DocumentFunctionCall::evaluate(txIEvalContext* aContext) { NodeSet* nodeSet = new NodeSet(); // document(object, node-set?) - if (requireParams(1, 2, cs)) { + if (requireParams(1, 2, aContext)) { ListIterator* iter = params.iterator(); Expr* param1 = (Expr*) iter->next(); - ExprResult* exprResult1 = param1->evaluate(context, cs); + ExprResult* exprResult1 = param1->evaluate(aContext); String baseURI; MBool baseURISet = MB_FALSE; @@ -76,11 +75,12 @@ ExprResult* DocumentFunctionCall::evaluate(Node* context, ContextState* cs) // We have 2 arguments, get baseURI from the first node // in the resulting nodeset Expr* param2 = (Expr*) iter->next(); - ExprResult* exprResult2 = param2->evaluate(context, cs); + ExprResult* exprResult2 = param2->evaluate(aContext); if (exprResult2->getResultType() != ExprResult::NODESET) { String err("node-set expected as second argument to document(): "); toString(err); - cs->recieveError(err); + aContext->receiveError(err, NS_ERROR_XPATH_INVALID_ARG); + delete exprResult1; delete exprResult2; return nodeSet; } diff --git a/content/xslt/src/xslt/txElementAvailableFnCall.cpp b/content/xslt/src/xslt/txElementAvailableFnCall.cpp index 3b00c8e7e84a..2808637066f0 100644 --- a/content/xslt/src/xslt/txElementAvailableFnCall.cpp +++ b/content/xslt/src/xslt/txElementAvailableFnCall.cpp @@ -40,6 +40,7 @@ #include "XSLTFunctions.h" #include "XMLUtils.h" #include "Names.h" +#include "txIXPathContext.h" /* Implementation of XSLT 1.0 extension function: element-available @@ -47,9 +48,11 @@ /** * Creates a new element-available function call + * aNode is the Element in the stylesheet containing the + * Expr and is used for namespaceID resolution **/ -ElementAvailableFunctionCall::ElementAvailableFunctionCall() : - FunctionCall(ELEMENT_AVAILABLE_FN) +ElementAvailableFunctionCall::ElementAvailableFunctionCall(Element* aNode) : + mStylesheetNode(aNode), FunctionCall(ELEMENT_AVAILABLE_FN) { } @@ -61,24 +64,28 @@ ElementAvailableFunctionCall::ElementAvailableFunctionCall() : * @return the result of the evaluation * @see FunctionCall.h **/ -ExprResult* ElementAvailableFunctionCall::evaluate(Node* context, ContextState* cs) { +ExprResult* ElementAvailableFunctionCall::evaluate(txIEvalContext* aContext) +{ ExprResult* result = NULL; - if ( requireParams(1,1,cs) ) { + if (requireParams(1, 1, aContext)) { ListIterator iter(¶ms); Expr* param = (Expr*) iter.next(); - ExprResult* exprResult = param->evaluate(context, cs); + ExprResult* exprResult = param->evaluate(aContext); if (exprResult && exprResult->getResultType() == ExprResult::STRING) { String property; exprResult->stringValue(property); if (XMLUtils::isValidQName(property)) { - String prefix, propertyNsURI; + String prefix; + PRInt32 aNSID = kNameSpaceID_None; XMLUtils::getPrefix(property, prefix); if (!prefix.isEmpty()) { - cs->getNameSpaceURIFromPrefix(property, propertyNsURI); + txAtom* prefixAtom = TX_GET_ATOM(prefix); + aNSID = mStylesheetNode->lookupNamespaceID(prefixAtom); + TX_IF_RELEASE_ATOM(prefixAtom); } - if (propertyNsURI.isEqual(XSLT_NS)) { + if (aNSID == kNameSpaceID_XSLT) { String localName; XMLUtils::getLocalPart(property, localName); if ( localName.isEqual(APPLY_IMPORTS) || @@ -119,7 +126,7 @@ ExprResult* ElementAvailableFunctionCall::evaluate(Node* context, ContextState* } else { String err("Invalid argument passed to element-available(), expecting String"); - delete result; + aContext->receiveError(err, NS_ERROR_XPATH_INVALID_ARG); result = new StringResult(err); } delete exprResult; diff --git a/content/xslt/src/xslt/txFormatNumberFunctionCall.cpp b/content/xslt/src/xslt/txFormatNumberFunctionCall.cpp index 1c76314a28c4..b71ed2b97bf5 100644 --- a/content/xslt/src/xslt/txFormatNumberFunctionCall.cpp +++ b/content/xslt/src/xslt/txFormatNumberFunctionCall.cpp @@ -39,6 +39,7 @@ #include "XSLTFunctions.h" #include "primitives.h" #include "Names.h" +#include "txIXPathContext.h" #include #ifndef TX_EXE @@ -70,10 +71,9 @@ txFormatNumberFunctionCall::txFormatNumberFunctionCall(ProcessorState* aPs) : * for evaluation * @return the result of the evaluation */ -ExprResult* txFormatNumberFunctionCall::evaluate(Node* aContext, - ContextState* aCs) +ExprResult* txFormatNumberFunctionCall::evaluate(txIEvalContext* aContext) { - if (!requireParams(2, 3, aCs)) + if (!requireParams(2, 3, aContext)) return new StringResult(); // Get number and format @@ -83,16 +83,16 @@ ExprResult* txFormatNumberFunctionCall::evaluate(Node* aContext, String formatStr; String formatName; - value = evaluateToNumber((Expr*)iter.next(), aContext, aCs); - evaluateToString((Expr*)iter.next(), aContext, aCs, formatStr); + value = evaluateToNumber((Expr*)iter.next(), aContext); + evaluateToString((Expr*)iter.next(), aContext, formatStr); if (iter.hasNext()) - evaluateToString((Expr*)iter.next(), aContext, aCs, formatName); + evaluateToString((Expr*)iter.next(), aContext, formatName); txDecimalFormat* format = mPs->getDecimalFormat(formatName); if (!format) { String err("unknown decimal format for: "); toString(err); - aCs->recieveError(err); + aContext->receiveError(err, NS_ERROR_XPATH_INVALID_ARG); return new StringResult(err); } @@ -161,7 +161,8 @@ ExprResult* txFormatNumberFunctionCall::evaluate(Node* aContext, else { String err(INVALID_PARAM_VALUE); toString(err); - aCs->recieveError(err); + aContext->receiveError(err, + NS_ERROR_XPATH_EVAL_FAILED); return new StringResult(err); } } @@ -171,7 +172,8 @@ ExprResult* txFormatNumberFunctionCall::evaluate(Node* aContext, else { String err(INVALID_PARAM_VALUE); toString(err); - aCs->recieveError(err); + aContext->receiveError(err, + NS_ERROR_XPATH_EVAL_FAILED); return new StringResult(err); } } @@ -256,7 +258,8 @@ ExprResult* txFormatNumberFunctionCall::evaluate(Node* aContext, groupSize == 0) { String err(INVALID_PARAM_VALUE); toString(err); - aCs->recieveError(err); + aContext->receiveError(err, + NS_ERROR_XPATH_EVAL_FAILED); return new StringResult(err); } diff --git a/content/xslt/src/xslt/txFunctionAvailableFnCall.cpp b/content/xslt/src/xslt/txFunctionAvailableFnCall.cpp index c9cfd7413fc2..7258c6268d6c 100644 --- a/content/xslt/src/xslt/txFunctionAvailableFnCall.cpp +++ b/content/xslt/src/xslt/txFunctionAvailableFnCall.cpp @@ -41,6 +41,7 @@ #include "FunctionLib.h" #include "XMLUtils.h" #include "Names.h" +#include "txIXPathContext.h" /* Implementation of XSLT 1.0 extension function: function-available @@ -62,13 +63,14 @@ FunctionAvailableFunctionCall::FunctionAvailableFunctionCall() : * @return the result of the evaluation * @see FunctionCall.h **/ -ExprResult* FunctionAvailableFunctionCall::evaluate(Node* context, ContextState* cs) { +ExprResult* FunctionAvailableFunctionCall::evaluate(txIEvalContext* aContext) +{ ExprResult* result = NULL; - if ( requireParams(1,1,cs) ) { + if (requireParams(1, 1, aContext)) { ListIterator iter(¶ms); Expr* param = (Expr*)iter.next(); - ExprResult* exprResult = param->evaluate(context, cs); + ExprResult* exprResult = param->evaluate(aContext); if (exprResult && exprResult->getResultType() == ExprResult::STRING) { String property; @@ -119,7 +121,7 @@ ExprResult* FunctionAvailableFunctionCall::evaluate(Node* context, ContextState* } else { String err("Invalid argument passed to function-available, expecting String"); - delete result; + aContext->receiveError(err, NS_ERROR_XPATH_INVALID_ARG); result = new StringResult(err); } delete exprResult; diff --git a/content/xslt/src/xslt/txGenerateIdFunctionCall.cpp b/content/xslt/src/xslt/txGenerateIdFunctionCall.cpp index 593317703972..c193afe117f4 100644 --- a/content/xslt/src/xslt/txGenerateIdFunctionCall.cpp +++ b/content/xslt/src/xslt/txGenerateIdFunctionCall.cpp @@ -24,6 +24,7 @@ #include "XSLTFunctions.h" #include "Names.h" +#include "txIXPathContext.h" #ifdef TX_EXE #include #else @@ -55,10 +56,9 @@ GenerateIdFunctionCall::GenerateIdFunctionCall() * @return the result of the evaluation * @see FunctionCall.h **/ -ExprResult* GenerateIdFunctionCall::evaluate(Node* aContext, - ContextState* aCs) { - - if (!requireParams(0, 1, aCs)) +ExprResult* GenerateIdFunctionCall::evaluate(txIEvalContext* aContext) +{ + if (!requireParams(0, 1, aContext)) return new StringResult(); Node* node = 0; @@ -68,14 +68,14 @@ ExprResult* GenerateIdFunctionCall::evaluate(Node* aContext, txListIterator iter(¶ms); Expr* param = (Expr*)iter.next(); - ExprResult* exprResult = param->evaluate(aContext, aCs); + ExprResult* exprResult = param->evaluate(aContext); if (!exprResult) return 0; if (exprResult->getResultType() != ExprResult::NODESET) { String err("Invalid argument passed to generate-id(), " "expecting NodeSet"); - aCs->recieveError(err); + aContext->receiveError(err, NS_ERROR_XPATH_INVALID_ARG); delete exprResult; return new StringResult(err); } @@ -89,7 +89,7 @@ ExprResult* GenerateIdFunctionCall::evaluate(Node* aContext, delete exprResult; } else { - node = aContext; + node = aContext->getContextNode(); } // generate id for selected node diff --git a/content/xslt/src/xslt/txKeyFunctionCall.cpp b/content/xslt/src/xslt/txKeyFunctionCall.cpp index 0792360cb653..050cbe086405 100644 --- a/content/xslt/src/xslt/txKeyFunctionCall.cpp +++ b/content/xslt/src/xslt/txKeyFunctionCall.cpp @@ -21,6 +21,7 @@ #include "XSLTFunctions.h" #include "Names.h" #include "XMLDOMUtils.h" +#include "txSingleNodeContext.h" /* * txKeyFunctionCall @@ -44,9 +45,9 @@ txKeyFunctionCall::txKeyFunctionCall(ProcessorState* aPs) : * for evaluation * @return the result of the evaluation */ -ExprResult* txKeyFunctionCall::evaluate(Node* aContext, ContextState* aCs) +ExprResult* txKeyFunctionCall::evaluate(txIEvalContext* aContext) { - if (!aContext || !requireParams(2, 2, aCs)) + if (!aContext || !requireParams(2, 2, aContext)) return new StringResult("error"); NodeSet* res = new NodeSet; @@ -57,26 +58,27 @@ ExprResult* txKeyFunctionCall::evaluate(Node* aContext, ContextState* aCs) ListIterator iter(¶ms); String keyName; - evaluateToString((Expr*)iter.next(), aContext, aCs, keyName); + evaluateToString((Expr*)iter.next(), aContext, keyName); Expr* param = (Expr*) iter.next(); txXSLKey* key = mProcessorState->getKey(keyName); if (!key) { String err("No key with that name in: "); toString(err); - aCs->recieveError(err); + aContext->receiveError(err, NS_ERROR_INVALID_ARG); return res; } - ExprResult* exprResult = param->evaluate(aContext, aCs); + ExprResult* exprResult = param->evaluate(aContext); if (!exprResult) return res; Document* contextDoc; - if (aContext->getNodeType() == Node::DOCUMENT_NODE) - contextDoc = (Document*)aContext; + Node* contextNode = aContext->getContextNode(); + if (contextNode->getNodeType() == Node::DOCUMENT_NODE) + contextDoc = (Document*)contextNode; else - contextDoc = aContext->getOwnerDocument(); + contextDoc = contextNode->getOwnerDocument(); if (exprResult->getResultType() == ExprResult::NODESET) { NodeSet* nodeSet = (NodeSet*) exprResult; @@ -155,7 +157,7 @@ const NodeSet* txXSLKey::getNodes(String& aKeyValue, Document* aDoc) * @param aUse use-expression * @return MB_FALSE if an error occured, MB_TRUE otherwise */ -MBool txXSLKey::addKey(Pattern* aMatch, Expr* aUse) +MBool txXSLKey::addKey(txPattern* aMatch, Expr* aUse) { if (!aMatch || !aUse) return MB_FALSE; @@ -226,13 +228,12 @@ void txXSLKey::testNode(Node* aNode, NamedMap* aMap) while (iter.hasNext()) { Key* key=(Key*)iter.next(); - if (key->matchPattern->matches(aNode, 0, mProcessorState)) { - NodeSet contextNodeSet(aNode); - mProcessorState->getNodeSetStack()->push(&contextNodeSet); - mProcessorState->pushCurrentNode(aNode); - ExprResult* exprResult = key->useExpr->evaluate(aNode, mProcessorState); - mProcessorState->popCurrentNode(); - mProcessorState->getNodeSetStack()->pop(); + if (key->matchPattern->matches(aNode, mProcessorState)) { + txSingleNodeContext evalContext(aNode, mProcessorState); + txIEvalContext* prevCon = + mProcessorState->setEvalContext(&evalContext); + ExprResult* exprResult = key->useExpr->evaluate(&evalContext); + mProcessorState->setEvalContext(prevCon); if (exprResult->getResultType() == ExprResult::NODESET) { NodeSet* res = (NodeSet*)exprResult; for (int i=0; isize(); i++) { diff --git a/content/xslt/src/xslt/txNodeSorter.cpp b/content/xslt/src/xslt/txNodeSorter.cpp index bdf8c0aeee46..ef1167fc1450 100644 --- a/content/xslt/src/xslt/txNodeSorter.cpp +++ b/content/xslt/src/xslt/txNodeSorter.cpp @@ -43,6 +43,7 @@ #include "ProcessorState.h" #include "txXPathResultComparator.h" #include "txAtoms.h" +#include "txForwardContext.h" /* * Sorts Nodes as specified by the W3C XSLT 1.0 Recommendation @@ -84,9 +85,8 @@ MBool txNodeSorter::addSortElement(Element* aSortElement, key->mExpr = mPs->getExpr(aSortElement, ProcessorState::SelectAttr); else { if (!mDefaultExpr) { - String expr("."); - ExprParser parser; - mDefaultExpr = parser.createExpr(expr); + txNodeTest* test = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE); + mDefaultExpr = new LocationStep(test, LocationStep::SELF_AXIS); } key->mExpr = mDefaultExpr; } @@ -188,7 +188,7 @@ MBool txNodeSorter::sortNodeSet(NodeSet* aNodes) } iter.reset(); SortableNode* compNode = (SortableNode*)iter.next(); - while (compNode && (compareNodes(currNode, compNode) > 0)) { + while (compNode && (compareNodes(currNode, compNode, aNodes) > 0)) { compNode = (SortableNode*)iter.next(); } // ... and insert in sorted list @@ -211,7 +211,8 @@ MBool txNodeSorter::sortNodeSet(NodeSet* aNodes) } int txNodeSorter::compareNodes(SortableNode* aSNode1, - SortableNode* aSNode2) + SortableNode* aSNode2, + NodeSet* aNodes) { txListIterator iter(&mSortKeys); int i; @@ -221,9 +222,10 @@ int txNodeSorter::compareNodes(SortableNode* aSNode1, SortKey* key = (SortKey*)iter.next(); // Lazy create sort values if (!aSNode1->mSortValues[i]) { - mPs->pushCurrentNode(aSNode1->mNode); - ExprResult* res = key->mExpr->evaluate(aSNode1->mNode, mPs); - mPs->popCurrentNode(); + txForwardContext evalContext(mPs, aSNode1->mNode, aNodes); + txIEvalContext* priorEC = mPs->setEvalContext(&evalContext); + ExprResult* res = key->mExpr->evaluate(&evalContext); + mPs->setEvalContext(priorEC); if (!res) { // XXX ErrorReport return -1; @@ -236,9 +238,10 @@ int txNodeSorter::compareNodes(SortableNode* aSNode1, delete res; } if (!aSNode2->mSortValues[i]) { - mPs->pushCurrentNode(aSNode2->mNode); - ExprResult* res = key->mExpr->evaluate(aSNode2->mNode, mPs); - mPs->popCurrentNode(); + txForwardContext evalContext(mPs, aSNode2->mNode, aNodes); + txIEvalContext* priorEC = mPs->setEvalContext(&evalContext); + ExprResult* res = key->mExpr->evaluate(&evalContext); + mPs->setEvalContext(priorEC); if (!res) { // XXX ErrorReport return -1; @@ -272,7 +275,7 @@ MBool txNodeSorter::getAttrAsAVT(Element* aSortElement, if (!aSortElement->getAttr(aAttrName, kNameSpaceID_None, attValue)) return MB_FALSE; - mPs->processAttrValueTemplate(attValue, aContext, aResult); + mPs->processAttrValueTemplate(attValue, aSortElement, aResult); return MB_TRUE; } diff --git a/content/xslt/src/xslt/txNodeSorter.h b/content/xslt/src/xslt/txNodeSorter.h index 3e5e2aaf5d46..536698a238a6 100644 --- a/content/xslt/src/xslt/txNodeSorter.h +++ b/content/xslt/src/xslt/txNodeSorter.h @@ -83,7 +83,8 @@ private: }; int compareNodes(SortableNode* sNode1, - SortableNode* sNode2); + SortableNode* sNode2, + NodeSet* aNodes); MBool getAttrAsAVT(Element* aSortElement, txAtom* aAttrName, diff --git a/content/xslt/src/xslt/txPatternParser.cpp b/content/xslt/src/xslt/txPatternParser.cpp new file mode 100644 index 000000000000..7077631eef3e --- /dev/null +++ b/content/xslt/src/xslt/txPatternParser.cpp @@ -0,0 +1,339 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TransforMiiX XSLT Processor. + * + * The Initial Developer of the Original Code is + * Axel Hecht. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "txXSLTPatterns.h" +#include "txPatternParser.h" +#include "Names.h" +#include "txAtoms.h" + +txPattern* txPatternParser::createPattern(const String& aPattern, + txIParseContext* aContext, + ProcessorState* aPs) +{ + txPattern* pattern = 0; + ExprLexer lexer(aPattern); + nsresult rv = createUnionPattern(lexer, aContext, aPs, pattern); + if (NS_FAILED(rv)) { + // XXX error report parsing error + return 0; + } + return pattern; +} + +nsresult txPatternParser::createUnionPattern(ExprLexer& aLexer, + txIParseContext* aContext, + ProcessorState* aPs, + txPattern*& aPattern) +{ + nsresult rv = NS_OK; + txPattern* locPath = 0; + + rv = createLocPathPattern(aLexer, aContext, aPs, locPath); + if (NS_FAILED(rv)) + return rv; + + short type = aLexer.peek()->type; + if (type == Token::END) { + aPattern = locPath; + return NS_OK; + } + + if (type != Token::UNION_OP) { + delete locPath; + return NS_ERROR_XPATH_PARSE_FAILED; + } + + txUnionPattern* unionPattern = new txUnionPattern(); + if (!unionPattern) { + delete locPath; + return NS_ERROR_OUT_OF_MEMORY; + } + rv = unionPattern->addPattern(locPath); +#if 0 // XXX addPattern can't fail yet, it doesn't check for mem + if (NS_FAILED(rv)) { + delete unionPattern; + delete locPath; + return rv; + } +#endif + + aLexer.nextToken(); + do { + rv = createLocPathPattern(aLexer, aContext, aPs, locPath); + if (NS_FAILED(rv)) { + delete unionPattern; + return rv; + } + rv = unionPattern->addPattern(locPath); +#if 0 // XXX addPattern can't fail yet, it doesn't check for mem + if (NS_FAILED(rv)) { + delete unionPattern; + delete locPath; + return rv; + } +#endif + type = aLexer.nextToken()->type; + } while (type == Token::UNION_OP); + + if (type != Token::END) { + delete unionPattern; + return NS_ERROR_XPATH_PARSE_FAILED; + } + + aPattern = unionPattern; + return NS_OK; +} + +nsresult txPatternParser::createLocPathPattern(ExprLexer& aLexer, + txIParseContext* aContext, + ProcessorState* aPs, + txPattern*& aPattern) +{ + nsresult rv = NS_OK; + + MBool isChild = MB_TRUE; + MBool isAbsolute = MB_FALSE; + txPattern* stepPattern = 0; + txLocPathPattern* pathPattern = 0; + + short type = aLexer.peek()->type; + switch (type) { + case Token::ANCESTOR_OP: + isChild = MB_FALSE; + isAbsolute = MB_TRUE; + aLexer.nextToken(); + break; + case Token::PARENT_OP: + aLexer.nextToken(); + isAbsolute = MB_TRUE; + if (aLexer.peek()->type == Token::END || + aLexer.peek()->type == Token::UNION_OP) { + aPattern = new txRootPattern(MB_TRUE); + return aPattern ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + } + break; + case Token::FUNCTION_NAME: + // id(Literal) or key(Literal, Literal) + { + String& name = aLexer.nextToken()->value; + txAtom* nameAtom = TX_GET_ATOM(name); + if (nameAtom == txXPathAtoms::id) { + rv = createIdPattern(aLexer, stepPattern); + } + else if (nameAtom == txXSLTAtoms::key) { + rv = createKeyPattern(aLexer, aContext, aPs, stepPattern); + } + TX_IF_RELEASE_ATOM(nameAtom); + if (NS_FAILED(rv)) + return rv; + } + break; + default: + break; + } + if (!stepPattern) { + rv = createStepPattern(aLexer, aContext, stepPattern); + if (NS_FAILED(rv)) + return rv; + } + + type = aLexer.peek()->type; + if (!isAbsolute && type != Token::PARENT_OP + && type != Token::ANCESTOR_OP) { + aPattern = stepPattern; + return NS_OK; + } + + pathPattern = new txLocPathPattern(); + if (!pathPattern) { + delete stepPattern; + return NS_ERROR_OUT_OF_MEMORY; + } + + if (isAbsolute) { + txRootPattern* root = new txRootPattern(MB_FALSE); + if (!root) { + delete stepPattern; + delete pathPattern; + return NS_ERROR_OUT_OF_MEMORY; + } + rv = pathPattern->addStep(root, isChild); + if (NS_FAILED(rv)) { + delete stepPattern; + delete pathPattern; + delete root; + return NS_ERROR_OUT_OF_MEMORY; + } + } + + rv = pathPattern->addStep(stepPattern, isChild); + if (NS_FAILED(rv)) { + delete stepPattern; + delete pathPattern; + return NS_ERROR_OUT_OF_MEMORY; + } + stepPattern = 0; // stepPattern is part of pathPattern now + + while (type == Token::PARENT_OP || type == Token::ANCESTOR_OP) { + isChild = type == Token::PARENT_OP; + aLexer.nextToken(); + rv = createStepPattern(aLexer, aContext, stepPattern); + if (NS_FAILED(rv)) { + delete pathPattern; + return rv; + } + rv = pathPattern->addStep(stepPattern, isChild); + if (NS_FAILED(rv)) { + delete stepPattern; + delete pathPattern; + return NS_ERROR_OUT_OF_MEMORY; + } + stepPattern = 0; // stepPattern is part of pathPattern now + type = aLexer.peek()->type; + } + aPattern = pathPattern; + return rv; +} + +nsresult txPatternParser::createIdPattern(ExprLexer& aLexer, + txPattern*& aPattern) +{ + nsresult rv = NS_OK; + // check for '(' Literal ')' + if (aLexer.nextToken()->type != Token::L_PAREN && + aLexer.peek()->type != Token::LITERAL) + return NS_ERROR_XPATH_PARSE_FAILED; + const String& value = aLexer.nextToken()->value; + if (aLexer.nextToken()->type != Token::R_PAREN) + return NS_ERROR_XPATH_PARSE_FAILED; + aPattern = new txIdPattern(value); + return aPattern ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +nsresult txPatternParser::createKeyPattern(ExprLexer& aLexer, + txIParseContext* aContext, + ProcessorState* aPs, + txPattern*& aPattern) +{ + nsresult rv = NS_OK; + // check for '(' Literal, Literal ')' + if (aLexer.nextToken()->type != Token::L_PAREN && + aLexer.peek()->type != Token::LITERAL) + return NS_ERROR_XPATH_PARSE_FAILED; + const String& key = aLexer.nextToken()->value; + if (aLexer.nextToken()->type != Token::COMMA && + aLexer.peek()->type != Token::LITERAL) + return NS_ERROR_XPATH_PARSE_FAILED; + const String& value = aLexer.nextToken()->value; + if (aLexer.nextToken()->type != Token::R_PAREN) + return NS_ERROR_XPATH_PARSE_FAILED; + aPattern = new txKeyPattern(aPs, key, value); + return aPattern ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +nsresult txPatternParser::createStepPattern(ExprLexer& aLexer, + txIParseContext* aContext, + txPattern*& aPattern) +{ + nsresult rv = NS_OK; + MBool isAttr = MB_FALSE; + Token* tok = aLexer.peek(); + if (tok->type == Token::AXIS_IDENTIFIER) { + if (ATTRIBUTE_AXIS.isEqual(tok->value)) { + isAttr = MB_TRUE; + } + else if (!CHILD_AXIS.isEqual(tok->value)) { + // all done already for CHILD_AXIS, for all others + // XXX report unexpected axis error + return NS_ERROR_XPATH_PARSE_FAILED; + } + aLexer.nextToken(); + } + else if (tok->type == Token::AT_SIGN) { + aLexer.nextToken(); + isAttr = MB_TRUE; + } + tok = aLexer.nextToken(); + + txNodeTest* nodeTest = 0; + if (tok->type == Token::CNAME) { + // resolve QName + txAtom *prefix, *lName; + PRInt32 nspace; + rv = resolveQName(tok->value, prefix, aContext, lName, nspace); + if (NS_FAILED(rv)) { + // XXX error report namespace resolve failed + return rv; + } + if (isAttr) { + nodeTest = new txNameTest(prefix, lName, nspace, + Node::ATTRIBUTE_NODE); + } + else { + nodeTest = new txNameTest(prefix, lName, nspace, + Node::ELEMENT_NODE); + } + TX_IF_RELEASE_ATOM(prefix); + TX_IF_RELEASE_ATOM(lName); + if (!nodeTest) { + return NS_ERROR_OUT_OF_MEMORY; + } + } + else { + aLexer.pushBack(); + nodeTest = createNodeTypeTest(aLexer); + if (!nodeTest) { + // XXX error report NodeTest expected + return NS_ERROR_XPATH_PARSE_FAILED; + } + } + + txStepPattern* step = new txStepPattern(nodeTest, isAttr); + if (!step) { + delete nodeTest; + return NS_ERROR_OUT_OF_MEMORY; + } + nodeTest = 0; + if (!parsePredicates(step, aLexer, aContext)) { + delete step; + return NS_ERROR_XPATH_PARSE_FAILED; + } + + aPattern = step; + return NS_OK; +} diff --git a/content/xslt/src/xslt/txPatternParser.h b/content/xslt/src/xslt/txPatternParser.h new file mode 100644 index 000000000000..fc4731cd56ca --- /dev/null +++ b/content/xslt/src/xslt/txPatternParser.h @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TransforMiiX XSLT Processor. + * + * The Initial Developer of the Original Code is + * Axel Hecht. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef TX_PATTERNPARSER_H +#define TX_PATTERNPARSER_H + +#include "txXSLTPatterns.h" +#include "ExprParser.h" + +class txPatternParser : public ExprParser +{ +public: + static txPattern* createPattern(const String& aPattern, + txIParseContext* aContext, + ProcessorState* aPs); +protected: + static nsresult createUnionPattern(ExprLexer& aLexer, + txIParseContext* aContext, + ProcessorState* aPs, + txPattern*& aPattern); + static nsresult createLocPathPattern(ExprLexer& aLexer, + txIParseContext* aContext, + ProcessorState* aPs, + txPattern*& aPattern); + static nsresult createIdPattern(ExprLexer& aLexer, + txPattern*& aPattern); + static nsresult createKeyPattern(ExprLexer& aLexer, + txIParseContext* aContext, + ProcessorState* aPs, + txPattern*& aPattern); + static nsresult createStepPattern(ExprLexer& aLexer, + txIParseContext* aContext, + txPattern*& aPattern); +}; + +#endif // TX_PATTERNPARSER_H diff --git a/content/xslt/src/xslt/txSystemPropertyFunctionCall.cpp b/content/xslt/src/xslt/txSystemPropertyFunctionCall.cpp index db6ed23c9b8f..79cc50a2472f 100644 --- a/content/xslt/src/xslt/txSystemPropertyFunctionCall.cpp +++ b/content/xslt/src/xslt/txSystemPropertyFunctionCall.cpp @@ -1,6 +1,7 @@ #include "XSLTFunctions.h" #include "XMLUtils.h" #include "Names.h" +#include "txIXPathContext.h" const String XSL_VERSION_PROPERTY = "version"; const String XSL_VENDOR_PROPERTY = "vendor"; @@ -12,9 +13,11 @@ const String XSL_VENDOR_URL_PROPERTY = "vendor-url"; /** * Creates a new system-property function call + * aNode is the Element in the stylesheet containing the + * Expr and is used for namespaceID resolution **/ -SystemPropertyFunctionCall::SystemPropertyFunctionCall() : - FunctionCall(SYSTEM_PROPERTY_FN) +SystemPropertyFunctionCall::SystemPropertyFunctionCall(Element* aNode) : + mStylesheetNode(aNode), FunctionCall(SYSTEM_PROPERTY_FN) { } @@ -26,22 +29,29 @@ SystemPropertyFunctionCall::SystemPropertyFunctionCall() : * @return the result of the evaluation * @see FunctionCall.h **/ -ExprResult* SystemPropertyFunctionCall::evaluate(Node* context, ContextState* cs) { +ExprResult* SystemPropertyFunctionCall::evaluate(txIEvalContext* aContext) +{ ExprResult* result = NULL; - if ( requireParams(1,1,cs) ) { + if (requireParams(1, 1, aContext)) { ListIterator* iter = params.iterator(); Expr* param = (Expr*) iter->next(); delete iter; - ExprResult* exprResult = param->evaluate(context, cs); + ExprResult* exprResult = param->evaluate(aContext); if (exprResult->getResultType() == ExprResult::STRING) { String property; exprResult->stringValue(property); if (XMLUtils::isValidQName(property)) { - String propertyNsURI, prefix; + String prefix; + PRInt32 namespaceID = kNameSpaceID_None; XMLUtils::getPrefix(property, prefix); - cs->getNameSpaceURIFromPrefix(prefix, propertyNsURI); - if (propertyNsURI.isEqual(XSLT_NS)) { + if (!prefix.isEmpty()) { + txAtom* prefixAtom = TX_GET_ATOM(prefix); + namespaceID = + mStylesheetNode->lookupNamespaceID(prefixAtom); + TX_IF_RELEASE_ATOM(prefixAtom); + } + if (namespaceID == kNameSpaceID_XSLT) { String localName; XMLUtils::getLocalPart(property, localName); if (localName.isEqual(XSL_VERSION_PROPERTY)) @@ -55,6 +65,7 @@ ExprResult* SystemPropertyFunctionCall::evaluate(Node* context, ContextState* cs } else { String err("Invalid argument passed to system-property(), expecting String"); + aContext->receiveError(err, NS_ERROR_XPATH_INVALID_ARG); result = new StringResult(err); } } diff --git a/content/xslt/src/xslt/txXSLTFunctions.h b/content/xslt/src/xslt/txXSLTFunctions.h index 13a921d4ae2c..27f87ad856c9 100644 --- a/content/xslt/src/xslt/txXSLTFunctions.h +++ b/content/xslt/src/xslt/txXSLTFunctions.h @@ -51,14 +51,9 @@ public: DocumentFunctionCall(ProcessorState* aPs, Node* aDefResolveNode); /** - * Evaluates this Expr based on the given context node and processor state - * @param context the context node for evaluation of this Expr - * @param cs the ContextState containing the stack information needed - * for evaluation - * @return the result of the evaluation - * @see FunctionCall.h + * Virtual methods from FunctionCall **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); + ExprResult* evaluate(txIEvalContext* aContext); private: ProcessorState* mProcessorState; @@ -80,12 +75,10 @@ public: /* * Evaluates a key() xslt-functioncall. First argument is name of key * to use, second argument is value to look up. - * @param aContext the context node for evaluation of this Expr - * @param aCs the ContextState containing the stack information needed - * for evaluation - * @return the result of the evaluation + * + * Virtual function from FunctionCall */ - virtual ExprResult* evaluate(Node* aContext, ContextState* aCs); + ExprResult* evaluate(txIEvalContext* aContext); private: ProcessorState* mProcessorState; @@ -120,7 +113,7 @@ public: * @param aUse use-expression * @return MB_FALSE if an error occured, MB_TRUE otherwise */ - MBool addKey(Pattern* aMatch, Expr* aUse); + MBool addKey(txPattern* aMatch, Expr* aUse); private: /* @@ -150,7 +143,7 @@ private: * represents one match/use pair */ struct Key { - Pattern* matchPattern; + txPattern* matchPattern; Expr* useExpr; }; @@ -191,14 +184,9 @@ public: txFormatNumberFunctionCall(ProcessorState* aPs); /** - * Evaluates this Expr based on the given context node and processor state - * @param aContext the context node for evaluation of this Expr - * @param aCs the ContextState containing the stack information needed - * for evaluation - * @return the result of the evaluation - * @see FunctionCall.h + * Virtual function from FunctionCall **/ - virtual ExprResult* evaluate(Node* aContext, ContextState* aCs); + ExprResult* evaluate(txIEvalContext* aContext); private: static const UNICODE_CHAR FORMAT_QUOTE; @@ -255,17 +243,12 @@ public: CurrentFunctionCall(ProcessorState* ps); /** - * Evaluates this Expr based on the given context node and processor state - * @param context the context node for evaluation of this Expr - * @param cs the ContextState containing the stack information needed - * for evaluation - * @return the result of the evaluation - * @see FunctionCall.h + * Virtual function from FunctionCall **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); + ExprResult* evaluate(txIEvalContext* aContext); private: - ProcessorState* processorState; + ProcessorState* mPs; }; /** @@ -288,7 +271,7 @@ public: * @return the result of the evaluation * @see FunctionCall.h **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); + ExprResult* evaluate(txIEvalContext* aContext); private: }; @@ -313,7 +296,7 @@ public: * @return the result of the evaluation * @see FunctionCall.h **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); + ExprResult* evaluate(txIEvalContext* aContext); private: static const char printfFmt[]; @@ -328,8 +311,10 @@ public: /** * Creates a new system-property() function call + * aNode is the Element in the stylesheet containing the + * Expr and is used for namespaceID resolution **/ - SystemPropertyFunctionCall(); + SystemPropertyFunctionCall(Element* aNode); /** * Evaluates this Expr based on the given context node and processor state @@ -339,9 +324,13 @@ public: * @return the result of the evaluation * @see FunctionCall.h **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); + ExprResult* evaluate(txIEvalContext* aContext); private: + /* + * resolve namespaceIDs with this node + */ + Element* mStylesheetNode; }; /** @@ -353,8 +342,10 @@ public: /** * Creates a new element-available() function call + * aNode is the Element in the stylesheet containing the + * Expr and is used for namespaceID resolution **/ - ElementAvailableFunctionCall(); + ElementAvailableFunctionCall(Element* aNode); /** * Evaluates this Expr based on the given context node and processor state @@ -364,9 +355,13 @@ public: * @return the result of the evaluation * @see FunctionCall.h **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); + ExprResult* evaluate(txIEvalContext* aContext); private: + /* + * resolve namespaceIDs with this node + */ + Element* mStylesheetNode; }; /** @@ -389,7 +384,7 @@ public: * @return the result of the evaluation * @see FunctionCall.h **/ - virtual ExprResult* evaluate(Node* context, ContextState* cs); + ExprResult* evaluate(txIEvalContext* aContext); private: }; diff --git a/content/xslt/src/xslt/txXSLTPatterns.cpp b/content/xslt/src/xslt/txXSLTPatterns.cpp new file mode 100644 index 000000000000..59a60f8e94d9 --- /dev/null +++ b/content/xslt/src/xslt/txXSLTPatterns.cpp @@ -0,0 +1,614 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TransforMiiX XSLT Processor. + * + * The Initial Developer of the Original Code is + * Axel Hecht. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "txXSLTPatterns.h" +#include "txNodeSetContext.h" +#include "txForwardContext.h" +#include "XSLTFunctions.h" +#ifndef TX_EXE +#include "nsReadableUtils.h" +#include "nsIContent.h" +#include "nsINodeInfo.h" +#endif + +/* + * txPattern + * + * Base class of all patterns + * Implements only a default getSimplePatterns + */ +nsresult txPattern::getSimplePatterns(txList& aList) +{ + aList.add(this); + return NS_OK; +} + +txPattern::~txPattern() +{ +} + + +/* + * txUnionPattern + * + * This pattern is returned by the parser for "foo | bar" constructs. + * |xsl:template|s should use the simple patterns + */ + +/* + * Destructor, deletes all LocationPathPatterns + */ +txUnionPattern::~txUnionPattern() +{ + ListIterator iter(&mLocPathPatterns); + while (iter.hasNext()) { + delete (txPattern*)iter.next(); + } +} + +nsresult txUnionPattern::addPattern(txPattern* aPattern) +{ + if (!aPattern) + return NS_ERROR_NULL_POINTER; + mLocPathPatterns.add(aPattern); + return NS_OK; +} + +/* + * Returns the default priority of this Pattern. + * UnionPatterns don't like this. + * This should be called on the simple patterns. + */ +double txUnionPattern::getDefaultPriority() +{ + NS_ASSERTION(0, "Don't call getDefaultPriority on txUnionPattern"); + return Double::NaN; +} + +/* + * Determines whether this Pattern matches the given node within + * the given context + * 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) +{ + ListIterator iter(&mLocPathPatterns); + while (iter.hasNext()) { + txPattern* p = (txPattern*)iter.next(); + if (p->matches(aNode, aContext)) { + return MB_TRUE; + } + } + return MB_FALSE; +} + +nsresult txUnionPattern::getSimplePatterns(txList& aList) +{ + ListIterator iter(&mLocPathPatterns); + while (iter.hasNext()) { + aList.add(iter.next()); + iter.remove(); + } + return NS_OK; +} + +/* + * The String representation will be appended to any data in the + * destination String, to allow cascading calls to other + * toString() methods for mLocPathPatterns. + */ +void txUnionPattern::toString(String& aDest) +{ +#ifdef DEBUG + aDest.append("txUnionPattern{"); +#endif + txListIterator iter(&mLocPathPatterns); + if (iter.hasNext()) + ((txPattern*)iter.next())->toString(aDest); + while (iter.hasNext()) { + aDest.append(" | "); + ((txPattern*)iter.next())->toString(aDest); + } +#ifdef DEBUG + aDest.append("}"); +#endif +} // toString + + +/* + * LocationPathPattern + * + * a list of step patterns, can start with id or key + * (dealt with by the parser) + */ + +/* + * Destructor, deletes all PathPatterns + */ +txLocPathPattern::~txLocPathPattern() +{ + ListIterator iter(&mSteps); + while (iter.hasNext()) { + delete (Step*)iter.next(); + } +} + +nsresult txLocPathPattern::addStep(txPattern* aPattern, MBool isChild) +{ + if (!aPattern) + return NS_ERROR_NULL_POINTER; + Step* step = new Step(aPattern, isChild); + if (!step) + return NS_ERROR_OUT_OF_MEMORY; + mSteps.add(step); + return NS_OK; +} + +MBool txLocPathPattern::matches(Node* aNode, txIMatchContext* aContext) +{ + NS_ASSERTION(aNode && mSteps.getLength(), "Internal error"); + + /* + * The idea is to split up a path into blocks separated by descendant + * operators. For example "foo/bar//baz/bop//ying/yang" is split up into + * three blocks. The "ying/yang" block is handled by the first while-loop + * and the "foo/bar" and "baz/bop" blocks are handled by the second + * while-loop. + * A block is considered matched when we find a list of ancestors that + * match the block. If there are more than one list of ancestors that + * match a block we only need to find the one furthermost down in the + * tree. + */ + + ListIterator iter(&mSteps); + iter.resetToEnd(); + + Step* step; + step = (Step*)iter.previous(); + if (!step->pattern->matches(aNode, aContext)) + return MB_FALSE; + Node* node = aNode->getXPathParent(); + + while (step->isChild) { + step = (Step*)iter.previous(); + if (!step) + return MB_TRUE; // all steps matched + if (!node || !step->pattern->matches(node, aContext)) + return MB_FALSE; // no more ancestors or no match + + node = node->getXPathParent(); + } + + // We have at least one // path separator + Node *blockStart = node; + txListIterator blockIter(iter); + + while ((step = (Step*)iter.previous())) { + if (!node) + return MB_FALSE; // There are more steps in the current block + // than ancestors of the tested node + + if (!step->pattern->matches(node, aContext)) { + // Didn't match. We restart at beginning of block using a new + // start node + iter = blockIter; + blockStart = blockStart->getXPathParent(); + node = blockStart; + } + else { + node = node->getXPathParent(); + if (!step->isChild) { + // We've matched an entire block. Set new start iter and start node + blockIter = iter; + blockStart = node; + } + } + } + + return MB_TRUE; +} // txLocPathPattern::matches + +double txLocPathPattern::getDefaultPriority() +{ + if (mSteps.getLength() > 1) { + return 0.5; + } + + return ((Step*)mSteps.get(0))->pattern->getDefaultPriority(); +} + +void txLocPathPattern::toString(String& aDest) +{ + ListIterator iter(&mSteps); +#ifdef DEBUG + aDest.append("txLocPathPattern{"); +#endif + Step* step; + step = (Step*)iter.next(); + if (step) { + step->pattern->toString(aDest); + } + while ((step = (Step*)iter.next())) { + if (step->isChild) + aDest.append("/"); + else + aDest.append("//"); + step->pattern->toString(aDest); + } +#ifdef DEBUG + aDest.append("}"); +#endif +} // txLocPathPattern::toString + +/* + * txRootPattern + * + * a txPattern matching the document node, or '/' + */ + +txRootPattern::~txRootPattern() +{ +} + +MBool txRootPattern::matches(Node* aNode, txIMatchContext* aContext) +{ + return aNode && (aNode->getNodeType() == Node::DOCUMENT_NODE); +} + +double txRootPattern::getDefaultPriority() +{ + return 0.5; +} + +void txRootPattern::toString(String& aDest) +{ +#ifdef DEBUG + aDest.append("txRootPattern{"); +#endif + if (mSerialize) + aDest.append("/"); +#ifdef DEBUG + aDest.append("}"); +#endif +} + +/* + * txIdPattern + * + * txIdPattern matches if the given node has a ID attribute with one + * of the space delimited values. + * This looks like the id() function, but may only have LITERALs as + * argument. + */ + +#define TX_IS_WHITE(c) (c == ' ' || c == '\r' || c == '\n'|| c == '\t') + +txIdPattern::txIdPattern(const String aString) +{ +#ifdef TX_EXE + mIds = aString; +#else + const nsString& ids = aString.getConstNSString(); + nsAString::const_iterator pos, begin, end; + ids.BeginReading(begin); + ids.EndReading(end); + pos = begin; + while (pos != end) { + while (pos != end && TX_IS_WHITE(*pos)) + ++pos; + begin = pos; + if (!mIds.IsEmpty()) + mIds += PRUnichar(' '); + while (pos != end && !TX_IS_WHITE(*pos)) + ++pos; + mIds += Substring(begin, pos); + } +#endif +} + +txIdPattern::~txIdPattern() +{ +} + +MBool txIdPattern::matches(Node* aNode, txIMatchContext* aContext) +{ +#ifdef TX_EXE + return MB_FALSE; // not implemented +#else + if (aNode->getNodeType() != Node::ELEMENT_NODE) { + return MB_FALSE; + } + + // Get a ID attribute, if there is + + nsCOMPtr content = do_QueryInterface(aNode->getNSObj()); + NS_ASSERTION(content, "a Element without nsIContent"); + if (!content) { + return MB_FALSE; + } + nsCOMPtr ni; + content->GetNodeInfo(*getter_AddRefs(ni)); + if (!ni) { + return MB_FALSE; + } + nsCOMPtr idAttr; + ni->GetIDAttributeAtom(getter_AddRefs(idAttr)); + if (!idAttr) { + return MB_FALSE; // no ID for this element defined, can't match + } + nsAutoString value; + nsresult rv = content->GetAttr(kNameSpaceID_None, idAttr, value); + if (rv != NS_CONTENT_ATTR_HAS_VALUE) { + return MB_FALSE; // no ID attribute given + } + nsAString::const_iterator pos, begin, end; + mIds.BeginReading(begin); + mIds.EndReading(end); + pos = begin; + const PRUnichar space = PRUnichar(' '); + PRBool found = FindCharInReadable(space, pos, end); + + while (found) { + if (value.Equals(Substring(begin, pos))) { + return MB_TRUE; + } + ++pos; // skip ' ' + begin = pos; + found = FindCharInReadable(PRUnichar(' '), pos, end); + } + if (value.Equals(Substring(begin, pos))) { + return MB_TRUE; + } + return MB_FALSE; +#endif // TX_EXE +} + +double txIdPattern::getDefaultPriority() +{ + return 0.5; +} + +void txIdPattern::toString(String& aDest) +{ +#ifdef DEBUG + aDest.append("txIdPattern{"); +#endif + aDest.append("id('"); +#ifdef TX_EXE + aDest.append(mIds); +#else + aDest.append(mIds.get()); +#endif + aDest.append("')"); +#ifdef DEBUG + aDest.append("}"); +#endif +} + +/* + * txKeyPattern + * + * txKeyPattern matches if the given node is in the evalation of + * the key() function + * This resembles the key() function, but may only have LITERALs as + * argument. + */ + +txKeyPattern::~txKeyPattern() +{ +} + +MBool txKeyPattern::matches(Node* aNode, txIMatchContext* aContext) +{ + Document* contextDoc; + if (aNode->getNodeType() == Node::DOCUMENT_NODE) + contextDoc = (Document*)aNode; + else + contextDoc = aNode->getOwnerDocument(); + txXSLKey* key = mProcessorState->getKey(mName); + const NodeSet* nodes = key->getNodes(mValue, contextDoc); + if (!nodes || nodes->isEmpty()) + return MB_FALSE; + MBool isTrue = nodes->contains(aNode); + return isTrue; +} + +double txKeyPattern::getDefaultPriority() +{ + return 0.5; +} + +void txKeyPattern::toString(String& aDest) +{ +#ifdef DEBUG + aDest.append("txKeyPattern{"); +#endif + aDest.append("key('"); + aDest.append(mName); + aDest.append(", "); + aDest.append(mValue); + aDest.append("')"); +#ifdef DEBUG + aDest.append("}"); +#endif +} + +/* + * txStepPattern + * + * a txPattern to hold the NodeTest and the Predicates of a StepPattern + */ + +txStepPattern::~txStepPattern() +{ + delete mNodeTest; +} + +MBool txStepPattern::matches(Node* aNode, txIMatchContext* aContext) +{ + NS_ASSERTION(mNodeTest && aNode, "Internal error"); + if (!aNode) + return MB_FALSE; + + if (!mNodeTest->matches(aNode, aContext)) + return MB_FALSE; + + if (!mIsAttr && !aNode->getParentNode()) + return MB_FALSE; + if (isEmpty()) { + return MB_TRUE; + } + + /* + * Evaluate Predicates + * + * Copy all siblings/attributes matching mNodeTest to nodes + * Up to the last Predicate do + * Foreach node in nodes + * evaluate Predicate with node as context node + * if the result is a number, check the context position, + * otherwise convert to bool + * if result is true, copy node to newNodes + * if aNode is not member of newNodes, return MB_FALSE + * nodes = newNodes + * + * For the last Predicate, evaluate Predicate with aNode as + * context node, if the result is a number, check the position, + * otherwise return the result converted to boolean + */ + + // Create the context node set for evaluating the predicates + NodeSet nodes; + 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(); + } + } + + txListIterator iter(&predicates); + Expr* predicate = (Expr*)iter.next(); + NodeSet newNodes; + + while (iter.hasNext()) { + newNodes.clear(); + MBool contextIsInPredicate = MB_FALSE; + txNodeSetContext predContext(&nodes, aContext); + while (predContext.hasNext()) { + predContext.next(); + ExprResult* exprResult = predicate->evaluate(&predContext); + if (!exprResult) + break; + switch(exprResult->getResultType()) { + case ExprResult::NUMBER : + // handle default, [position() == numberValue()] + if ((double)predContext.position() == + exprResult->numberValue()) { + Node* tmp = predContext.getContextNode(); + if (tmp == aNode) + contextIsInPredicate = MB_TRUE; + newNodes.append(tmp); + } + break; + default: + if (exprResult->booleanValue()) { + Node* tmp = predContext.getContextNode(); + if (tmp == aNode) + contextIsInPredicate = MB_TRUE; + newNodes.append(tmp); + } + break; + } + delete exprResult; + } + // Move new NodeSet to the current one + nodes.clear(); + nodes.append(&newNodes); + if (!contextIsInPredicate) { + return MB_FALSE; + } + predicate = (Expr*)iter.next(); + } + txForwardContext evalContext(aContext, aNode, &nodes); + ExprResult* exprResult = predicate->evaluate(&evalContext); + if (!exprResult) + return MB_FALSE; + if (exprResult->getResultType() == ExprResult::NUMBER) + // handle default, [position() == numberValue()] + return ((double)evalContext.position() == exprResult->numberValue()); + + return exprResult->booleanValue(); +} // matches + +double txStepPattern::getDefaultPriority() +{ + if (isEmpty()) + return mNodeTest->getDefaultPriority(); + return 0.5; +} + +void txStepPattern::toString(String& aDest) +{ +#ifdef DEBUG + aDest.append("txStepPattern{"); +#endif + if (mIsAttr) + aDest.append("@"); + if (mNodeTest) + mNodeTest->toString(aDest); + + PredicateList::toString(aDest); +#ifdef DEBUG + aDest.append("}"); +#endif +} diff --git a/content/xslt/src/xslt/txXSLTPatterns.h b/content/xslt/src/xslt/txXSLTPatterns.h new file mode 100644 index 000000000000..d9c0ee865ff2 --- /dev/null +++ b/content/xslt/src/xslt/txXSLTPatterns.h @@ -0,0 +1,210 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TransforMiiX XSLT Processor. + * + * The Initial Developer of the Original Code is + * Axel Hecht. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef TX_XSLT_PATTERNS_H +#define TX_XSLT_PATTERNS_H + +#include "Expr.h" +class ProcessorState; + +class txPattern : public TxObject +{ +public: + virtual ~txPattern(); + + /* + * Determines whether this Pattern matches the given node. + */ + virtual MBool matches(Node* aNode, txIMatchContext* aContext) = 0; + + /* + * Returns the default priority of this Pattern. + * + * Simple Patterns return the values as specified in XPath 5.5. + * Returns -Inf for union patterns, as it shouldn't be called on them. + */ + virtual double getDefaultPriority() = 0; + + /* + * Returns the String representation of this Pattern. + * @param dest the String to use when creating the String + * representation. The String representation will be appended to + * any data in the destination String, to allow cascading calls to + * other #toString() methods for Patterns. + * @return the String representation of this Pattern. + */ + virtual void toString(String& aDest) = 0; + + /* + * Adds the simple Patterns to the List. + * For union patterns, add all sub patterns, + * all other (simple) patterns just add themselves. + * This cuts the ownership of the union pattern and it's + * simple patterns, leaving union patterns empty after a call + * to this function. + */ + virtual nsresult getSimplePatterns(txList &aList); +}; + +#define TX_DECL_PATTERN \ + MBool matches(Node* aNode, txIMatchContext* aContext); \ + double getDefaultPriority(); \ + void toString(String& aDest) +#define TX_DECL_PATTERN2 \ + TX_DECL_PATTERN; \ + nsresult getSimplePatterns(txList &aList) + + +class txUnionPattern : public txPattern +{ +public: + txUnionPattern() + { + } + + ~txUnionPattern(); + + nsresult addPattern(txPattern* aPattern); + + TX_DECL_PATTERN2; + +private: + txList mLocPathPatterns; +}; + +class txLocPathPattern : public txPattern +{ +public: + txLocPathPattern() + { + } + + ~txLocPathPattern(); + + nsresult addStep(txPattern* aPattern, MBool isChild); + + TX_DECL_PATTERN; + +private: + class Step { + public: + Step(txPattern* aPattern, MBool aIsChild) + : pattern(aPattern), isChild(aIsChild) + { + } + + ~Step() + { + delete pattern; + } + + txPattern* pattern; + MBool isChild; + }; + + txList mSteps; +}; + +class txRootPattern : public txPattern +{ +public: + txRootPattern(MBool aSerialize) : mSerialize(aSerialize) + { + } + + ~txRootPattern(); + + TX_DECL_PATTERN; +private: + // Don't serialize txRootPattern if it's used in a txLocPathPattern + MBool mSerialize; +}; + +class txIdPattern : public txPattern +{ +public: + txIdPattern(const String aString); + + ~txIdPattern(); + + TX_DECL_PATTERN; + +private: +#ifdef TX_EXE + String mIds; +#else + nsAutoString mIds; +#endif +}; + +class txKeyPattern : public txPattern +{ +public: + txKeyPattern(ProcessorState* aPs, const String& aName, + const String& aValue) + : mProcessorState(aPs), mName(aName), mValue(aValue) + { + } + + ~txKeyPattern(); + + TX_DECL_PATTERN; + +private: + ProcessorState* mProcessorState; + String mName, mValue; +}; + +class txStepPattern : public PredicateList, public txPattern +{ +public: + txStepPattern(txNodeTest* aNodeTest, MBool isAttr) + :mNodeTest(aNodeTest), mIsAttr(isAttr) + { + } + + ~txStepPattern(); + + TX_DECL_PATTERN; + +private: + txNodeTest* mNodeTest; + MBool mIsAttr; +}; + +#endif // TX_XSLT_PATTERNS_H