Fix for bug 151002 (abstract the content by a treewalker). Patch by me, with parts by Pike and sicking. r=sicking, sr=jst.

This commit is contained in:
peter%propagandism.org 2005-11-02 07:41:43 +00:00
Родитель df1d9c27bb
Коммит 6bb7249e06
58 изменённых файлов: 1424 добавлений и 1251 удалений

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

@ -37,6 +37,7 @@
* ***** END LICENSE BLOCK ***** */
#include "txExpandedNameMap.h"
#include "TxObject.h"
#include <string.h>
const int kTxExpandedNameMapAllocSize = 16;

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

@ -37,8 +37,8 @@
* ***** END LICENSE BLOCK ***** */
#include "txNamespaceMap.h"
#include "dom.h"
#include "txAtoms.h"
#include "txXPathNode.h"
txNamespaceMap::txNamespaceMap()
{

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

@ -82,7 +82,7 @@ public:
{
if (!mXML || !mStylesheet || !mOut)
return 1;
nsresult rv = transform(mXML, mStylesheet, *mOut, mObserver);
nsresult rv = transform(*mXML, mStylesheet, *mOut, mObserver);
return NS_FAILED(rv);
}
int closeOutput ()
@ -110,7 +110,7 @@ public:
delete mOut;
}
private:
Document *mXML;
txXPathNode *mXML;
nsRefPtr<txStylesheet> mStylesheet;
SimpleErrorObserver mObserver;
ofstream* mOut;

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

@ -35,12 +35,13 @@ REQUIRES += dom \
content \
widget \
unicharutil \
necko \
$(NULL)
endif
DIRS = dom parser
CPPSRCS = XMLDOMUtils.cpp XMLUtils.cpp
CPPSRCS = XMLUtils.cpp
include $(topsrcdir)/config/rules.mk

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

@ -149,6 +149,7 @@ class NodeList
class NodeListDefinition : public NodeList
{
friend class NamedNodeMap; //-- LF
friend class txXPathTreeWalker;
public:
NodeListDefinition();
virtual ~NodeListDefinition();
@ -188,6 +189,8 @@ class NamedNodeMap : public NodeListDefinition
private:
NodeListDefinition::ListItem* findListItemByName(const nsAString& name);
// txXPathTreeWalker is friend to speed up attr iterations
friend class txXPathTreeWalker;
};
//
@ -268,6 +271,8 @@ class NodeDefinition : public Node, public NodeList
protected:
friend class Document;
friend class txXPathTreeWalker;
friend class txXPathNodeUtils;
NodeDefinition(NodeType type, const nsAString& name,
const nsAString& value, Document* owner);
NodeDefinition(NodeType aType, const nsAString& aValue,

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

@ -24,6 +24,8 @@
#include "txXMLParser.h"
#include "txURIUtils.h"
#include "txXPathTreeWalker.h"
#ifndef TX_EXE
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
@ -42,7 +44,7 @@ class txXMLParser
{
public:
nsresult parse(istream& aInputStream, const nsAString& aUri,
Document** aResultDoc);
txXPathNode** aResultDoc);
const nsAString& getErrorString();
/**
@ -68,8 +70,8 @@ class txXMLParser
nsresult
txParseDocumentFromURI(const nsAString& aHref, const nsAString& aReferrer,
Document* aLoader, nsAString& aErrMsg,
Document** aResult)
const txXPathNode& aLoader, nsAString& aErrMsg,
txXPathNode** aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
*aResult = nsnull;
@ -78,9 +80,8 @@ txParseDocumentFromURI(const nsAString& aHref, const nsAString& aReferrer,
nsresult rv = NS_NewURI(getter_AddRefs(documentURI), aHref);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMDocument> theDocument;
nsCOMPtr<nsIDocument> loaderDocument =
do_QueryInterface(aLoader->getNSObj());
nsIDocument* loaderDocument = txXPathNativeNode::getDocument(aLoader);
nsCOMPtr<nsILoadGroup> loadGroup = loaderDocument->GetDocumentLoadGroup();
nsIURI *loaderUri = loaderDocument->GetDocumentURL();
NS_ENSURE_TRUE(loaderUri, NS_ERROR_FAILURE);
@ -97,7 +98,7 @@ txParseDocumentFromURI(const nsAString& aHref, const nsAString& aReferrer,
if (refUri) {
http->SetReferrer(refUri);
}
http->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
http->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
NS_LITERAL_CSTRING("text/xml,application/xml,application/xhtml+xml,*/*;q=0.1"),
PR_FALSE);
@ -108,15 +109,19 @@ txParseDocumentFromURI(const nsAString& aHref, const nsAString& aReferrer,
do_GetService("@mozilla.org/content/syncload-dom-service;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = loader->LoadDocumentAsXML(channel, loaderUri, getter_AddRefs(theDocument));
// Raw pointer, we want the resulting txXPathNode to hold a reference to
// the document.
nsIDOMDocument* theDocument = nsnull;
rv = loader->LoadDocumentAsXML(channel, loaderUri, &theDocument);
if (NS_FAILED(rv) || !theDocument) {
aErrMsg.Append(NS_LITERAL_STRING("Document load of ") +
aHref + NS_LITERAL_STRING(" failed."));
return rv;
}
*aResult = new Document(theDocument);
*aResult = txXPathNativeNode::createXPathNode(theDocument);
if (!*aResult) {
NS_RELEASE(theDocument);
return NS_ERROR_FAILURE;
}
@ -133,7 +138,7 @@ txParseDocumentFromURI(const nsAString& aHref, const nsAString& aReferrer,
#ifdef TX_EXE
nsresult
txParseFromStream(istream& aInputStream, const nsAString& aUri,
nsAString& aErrorString, Document** aResult)
nsAString& aErrorString, txXPathNode** aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
txXMLParser parser;
@ -211,7 +216,7 @@ externalEntityRefHandler(XML_Parser aParser,
*/
nsresult
txXMLParser::parse(istream& aInputStream, const nsAString& aUri,
Document** aResultDoc)
txXPathNode** aResultDoc)
{
mErrorString.Truncate();
*aResultDoc = nsnull;
@ -263,9 +268,9 @@ txXMLParser::parse(istream& aInputStream, const nsAString& aUri,
// clean up
XML_ParserFree(mExpatParser);
// ownership to the caller
*aResultDoc = mDocument;
*aResultDoc = txXPathNativeNode::createXPathNode(mDocument);
mDocument = nsnull;
return NS_OK;
return *aResultDoc ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
const nsAString&

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

@ -25,12 +25,15 @@
#ifndef MITRE_XMLPARSER_H
#define MITRE_XMLPARSER_H
#include "dom.h"
#include "baseutils.h"
#ifdef TX_EXE
#include <iostream.h>
#endif
class nsAString;
class txXPathNode;
/**
* API to load XML files into DOM datastructures.
* Parsing is either done by expat, or by expat via the synchloaderservice
@ -42,8 +45,8 @@
*/
extern "C" nsresult
txParseDocumentFromURI(const nsAString& aHref, const nsAString& aReferrer,
Document* aLoader, nsAString& aErrMsg,
Document** aResult);
const txXPathNode& aLoader, nsAString& aErrMsg,
txXPathNode** aResult);
#ifdef TX_EXE
/**
@ -51,6 +54,6 @@ txParseDocumentFromURI(const nsAString& aHref, const nsAString& aReferrer,
*/
extern "C" nsresult
txParseFromStream(istream& aInputStream, const nsAString& aUri,
nsAString& aErrorString, Document** aResult);
nsAString& aErrorString, txXPathNode** aResult);
#endif
#endif

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

@ -35,6 +35,7 @@
#include "txAtoms.h"
#include "txStringUtils.h"
#include "txNamespaceMap.h"
#include "txXPathTreeWalker.h"
/**
* Helper class for checking and partioning of QNames
@ -233,16 +234,6 @@ PRBool XMLUtils::isWhitespace(const nsAFlatString& aText)
return PR_TRUE;
}
/**
* Returns true if the given node's value has only whitespace characters
*/
PRBool XMLUtils::isWhitespace(Node* aNode)
{
nsAutoString text;
aNode->getNodeValue(text);
return isWhitespace(text);
}
/**
* Normalizes the value of a XML processing instruction
**/
@ -275,31 +266,21 @@ void XMLUtils::normalizePIValue(nsAString& piValue)
}
}
/*
* Walks up the document tree and returns true if the closest xml:space
* attribute is "preserve"
*/
//static
MBool XMLUtils::getXMLSpacePreserve(Node* aNode)
MBool XMLUtils::getXMLSpacePreserve(const txXPathNode& aNode)
{
NS_ASSERTION(aNode, "Calling preserveXMLSpace with NULL node!");
nsAutoString value;
Node* parent = aNode;
while (parent) {
if (parent->getNodeType() == Node::ELEMENT_NODE) {
Element* elem = (Element*)parent;
if (elem->getAttr(txXMLAtoms::space, kNameSpaceID_XML, value)) {
if (TX_StringEqualsAtom(value, txXMLAtoms::preserve)) {
return MB_TRUE;
}
if (TX_StringEqualsAtom(value, txXMLAtoms::_default)) {
return MB_FALSE;
}
txXPathTreeWalker walker(aNode);
do {
if (walker.getAttr(txXMLAtoms::space, kNameSpaceID_XML, value)) {
if (TX_StringEqualsAtom(value, txXMLAtoms::preserve)) {
return PR_TRUE;
}
if (TX_StringEqualsAtom(value, txXMLAtoms::_default)) {
return PR_FALSE;
}
}
parent = parent->getParentNode();
}
} while (walker.moveToParent());
return PR_FALSE;
}

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

@ -31,10 +31,10 @@
#define MITRE_XMLUTILS_H
#include "baseutils.h"
#include "dom.h"
#include "nsDependentSubstring.h"
#include "nsIAtom.h"
#include "txError.h"
#include "txXPathNode.h"
class txNamespaceMap;
@ -126,12 +126,6 @@ public:
*/
static PRBool isWhitespace(const nsAFlatString& aText);
/**
* Returns true if the given node's DOM nodevalue has only whitespace
* characters
*/
static PRBool isWhitespace(Node* aNode);
/**
* Normalizes the value of a XML processingInstruction
**/
@ -156,7 +150,7 @@ public:
* Walks up the document tree and returns true if the closest xml:space
* attribute is "preserve"
*/
static MBool getXMLSpacePreserve(Node* aNode);
static MBool getXMLSpacePreserve(const txXPathNode& aNode);
};
#endif

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

@ -79,7 +79,10 @@ CPPSRCS += nsXPathEvaluator.cpp \
nsXPathExpression.cpp \
nsXPathNSResolver.cpp \
nsXPathResult.cpp \
nsXPath1Scheme.cpp
nsXPath1Scheme.cpp \
txMozillaXPathTreeWalker.cpp
else
CPPSRCS += txStandaloneXPathTreeWalker.cpp
endif
include $(topsrcdir)/config/rules.mk

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

@ -48,7 +48,7 @@
#include "nsXPathResult.h"
#include "nsDOMError.h"
#include "txURIUtils.h"
#include "txXPathTreeWalker.h"
NS_IMPL_ADDREF(nsXPathExpression)
NS_IMPL_RELEASE(nsXPathExpression)
@ -112,16 +112,12 @@ nsXPathExpression::Evaluate(nsIDOMNode *aContextNode,
NS_ENSURE_ARG(aResult);
*aResult = nsnull;
nsCOMPtr<nsIDOMDocument> ownerDOMDocument;
aContextNode->GetOwnerDocument(getter_AddRefs(ownerDOMDocument));
if (!ownerDOMDocument) {
ownerDOMDocument = do_QueryInterface(aContextNode);
NS_ENSURE_TRUE(ownerDOMDocument, NS_ERROR_FAILURE);
nsAutoPtr<txXPathNode> contextNode(txXPathNativeNode::createXPathNode(aContextNode));
if (!contextNode) {
return NS_ERROR_OUT_OF_MEMORY;
}
Document document(ownerDOMDocument);
Node* node = document.createWrapper(aContextNode);
EvalContextImpl eContext(node, mRecycler);
EvalContextImpl eContext(*contextNode, mRecycler);
nsRefPtr<txAExprResult> exprResult;
rv = mExpression->evaluate(&eContext, getter_AddRefs(exprResult));
NS_ENSURE_SUCCESS(rv, rv);
@ -175,7 +171,7 @@ nsXPathExpression::EvalContextImpl::getVariable(PRInt32 aNamespace,
return NS_ERROR_INVALID_ARG;
}
MBool nsXPathExpression::EvalContextImpl::isStripSpaceAllowed(Node* aNode)
MBool nsXPathExpression::EvalContextImpl::isStripSpaceAllowed(const txXPathNode& aNode)
{
return MB_FALSE;
}
@ -198,7 +194,7 @@ void nsXPathExpression::EvalContextImpl::receiveError(const nsAString& aMsg,
// forward aMsg to console service?
}
Node* nsXPathExpression::EvalContextImpl::getContextNode()
const txXPathNode& nsXPathExpression::EvalContextImpl::getContextNode()
{
return mContextNode;
}

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

@ -46,6 +46,7 @@
#include "nsAutoPtr.h"
class Expr;
class txXPathNode;
/**
* A class for evaluating an XPath expression string
@ -70,7 +71,7 @@ private:
class EvalContextImpl : public txIEvalContext
{
public:
EvalContextImpl(Node* aContextNode, txResultRecycler* aRecycler)
EvalContextImpl(const txXPathNode& aContextNode, txResultRecycler* aRecycler)
: mContextNode(aContextNode),
mLastError(NS_OK),
mRecycler(aRecycler)
@ -89,7 +90,7 @@ private:
TX_DECL_EVAL_CONTEXT;
private:
Node* mContextNode;
const txXPathNode& mContextNode;
nsresult mLastError;
nsRefPtr<txResultRecycler> mRecycler;
};

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

@ -38,7 +38,6 @@
* ***** END LICENSE BLOCK ***** */
#include "nsXPathResult.h"
#include "dom.h"
#include "ExprResult.h"
#include "txNodeSet.h"
#include "nsDOMError.h"
@ -292,9 +291,9 @@ nsXPathResult::SetExprResult(txAExprResult* aExprResult, PRUint16 aResultType)
if (mResultType == FIRST_ORDERED_NODE_TYPE ||
mResultType == ANY_UNORDERED_NODE_TYPE) {
Node* node = nodeSet->get(0);
if (node)
rv = CallQueryInterface(node->getNSObj(), &mNode);
if (nodeSet->size() > 0) {
txXPathNativeNode::getNode(nodeSet->get(0), &mNode);
}
}
else {
if (mResultType == UNORDERED_NODE_ITERATOR_TYPE ||
@ -312,7 +311,7 @@ nsXPathResult::SetExprResult(txAExprResult* aExprResult, PRUint16 aResultType)
nsCOMPtr<nsIDOMNode> node;
PRInt32 i;
for (i = 0; i < count; ++i) {
node = do_QueryInterface(nodeSet->get(i)->getNSObj());
txXPathNativeNode::getNode(nodeSet->get(i), getter_AddRefs(node));
NS_ASSERTION(node, "node isn't an nsIDOMNode");
mElements->AppendObject(node);
}

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

@ -33,6 +33,7 @@
#include "txAtoms.h"
#include "txIXPathContext.h"
#include "txStringUtils.h"
#include "txXPathTreeWalker.h"
/**
* Creates a default BooleanFunctionCall, which always evaluates to False
@ -71,27 +72,27 @@ BooleanFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
if (!requireParams(1, 1, aContext))
return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
txXPathTreeWalker walker(aContext->getContextNode());
nsAutoString lang;
Node* node = aContext->getContextNode();
while (node) {
if (node->getNodeType() == Node::ELEMENT_NODE) {
Element* elem = (Element*)node;
if (elem->getAttr(txXMLAtoms::lang,
kNameSpaceID_XML, lang))
break;
}
node = node->getParentNode();
PRBool found;
do {
found = walker.getAttr(txXMLAtoms::lang, kNameSpaceID_XML,
lang);
} while (!found && walker.moveToParent());
if (!found) {
aContext->recycler()->getBoolResult(PR_FALSE, aResult);
return NS_OK;
}
MBool result = MB_FALSE;
if (node) {
nsAutoString arg;
evaluateToString((Expr*)iter.next(), aContext, arg);
result = arg.Equals(Substring(lang, 0, arg.Length()),
txCaseInsensitiveStringComparator()) &&
(lang.Length() == arg.Length() ||
lang.CharAt(arg.Length()) == '-');
}
nsAutoString arg;
evaluateToString((Expr*)iter.next(), aContext, arg);
PRBool result = arg.Equals(Substring(lang, 0, arg.Length()),
txCaseInsensitiveStringComparator()) &&
(lang.Length() == arg.Length() ||
lang.CharAt(arg.Length()) == '-');
aContext->recycler()->getBoolResult(result, aResult);

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

@ -36,7 +36,6 @@
#define TRANSFRMX_EXPR_H
#include "baseutils.h"
#include "dom.h"
#include "List.h"
#include "nsString.h"
#include "nsIAtom.h"
@ -53,6 +52,7 @@ class txIParseContext;
class txIMatchContext;
class txIEvalContext;
class txNodeSet;
class txXPathNode;
/**
* A Base Class for all XSL Expressions
@ -212,13 +212,14 @@ public:
* standalone. The NodeTest node() is different to the
* Pattern "node()" (document node isn't matched)
*/
virtual MBool matches(Node* aNode, txIMatchContext* aContext) = 0;
virtual PRBool matches(const txXPathNode& aNode,
txIMatchContext* aContext) = 0;
virtual double getDefaultPriority() = 0;
virtual void toString(nsAString& aDest) = 0;
};
#define TX_DECL_NODE_TEST \
MBool matches(Node* aNode, txIMatchContext* aContext); \
PRBool matches(const txXPathNode& aNode, txIMatchContext* aContext); \
double getDefaultPriority(); \
void toString(nsAString& aDest)
@ -233,7 +234,7 @@ public:
* principal node type
*/
txNameTest(nsIAtom* aPrefix, nsIAtom* aLocalName, PRInt32 aNSID,
Node::NodeType aNodeType);
PRUint16 aNodeType);
~txNameTest();
@ -243,7 +244,7 @@ private:
nsCOMPtr<nsIAtom> mPrefix;
nsCOMPtr<nsIAtom> mLocalName;
PRInt32 mNamespace;
Node::NodeType mNodeType;
PRUint16 mNodeType;
};
/*
@ -362,10 +363,10 @@ public:
TX_DECL_EXPR;
private:
void fromDescendants(Node* node, txIMatchContext* aContext,
txNodeSet* nodes);
void fromDescendantsRev(Node* node, txIMatchContext* aContext,
txNodeSet* nodes);
void fromDescendants(const txXPathNode& aNode, txIMatchContext* aCs,
txNodeSet* aNodes);
void fromDescendantsRev(const txXPathNode& aNode, txIMatchContext* aCs,
txNodeSet* aNodes);
nsAutoPtr<txNodeTest> mNodeTest;
LocationStepType mAxisIdentifier;
@ -619,7 +620,7 @@ private:
* Selects from the descendants of the context node
* all nodes that match the Expr
*/
nsresult evalDescendants(Expr* aStep, Node* aNode,
nsresult evalDescendants(Expr* aStep, const txXPathNode& aNode,
txIMatchContext* aContext,
txNodeSet* resNodes);
};

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

@ -45,7 +45,7 @@
#include "txAtoms.h"
#include "txIXPathContext.h"
#include "txStringUtils.h"
#include "txXPathNode.h"
/**
* Creates an Attribute Value Template using the given value
@ -692,11 +692,11 @@ txExprParser::createLocationStep(txExprLexer& lexer, txIParseContext* aContext,
switch (axisIdentifier) {
case LocationStep::ATTRIBUTE_AXIS:
nodeTest = new txNameTest(prefix, lName, nspace,
Node::ATTRIBUTE_NODE);
txXPathNodeType::ATTRIBUTE_NODE);
break;
default:
nodeTest = new txNameTest(prefix, lName, nspace,
Node::ELEMENT_NODE);
txXPathNodeType::ELEMENT_NODE);
break;
}
NS_ENSURE_TRUE(nodeTest, NS_ERROR_OUT_OF_MEMORY);

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

@ -39,7 +39,7 @@
#include "txForwardContext.h"
#include "txNodeSet.h"
Node* txForwardContext::getContextNode()
const txXPathNode& txForwardContext::getContextNode()
{
return mContextNode;
}
@ -63,7 +63,7 @@ nsresult txForwardContext::getVariable(PRInt32 aNamespace, nsIAtom* aLName,
return mInner->getVariable(aNamespace, aLName, aResult);
}
MBool txForwardContext::isStripSpaceAllowed(Node* aNode)
MBool txForwardContext::isStripSpaceAllowed(const txXPathNode& aNode)
{
NS_ASSERTION(mInner, "mInner is null!!!");
return mInner->isStripSpaceAllowed(aNode);

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

@ -41,12 +41,14 @@
#include "txIXPathContext.h"
#include "nsAutoPtr.h"
#include "txNodeSet.h"
class txNodeSet;
class txForwardContext : public txIEvalContext
{
public:
txForwardContext(txIMatchContext* aContext, Node* aContextNode,
txForwardContext(txIMatchContext* aContext,
const txXPathNode& aContextNode,
txNodeSet* aContextNodeSet)
: mInner(aContext),
mContextNode(aContextNode),
@ -59,7 +61,7 @@ public:
private:
txIMatchContext* mInner;
Node* mContextNode;
const txXPathNode& mContextNode;
nsRefPtr<txNodeSet> mContextSet;
};

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

@ -43,10 +43,12 @@
#include "nsIAtom.h"
#include "txError.h"
class txAExprResult;
class FunctionCall;
class Node;
class nsAString;
class nsIAtom;
class txAExprResult;
class txResultRecycler;
class txXPathNode;
/*
* txIParseContext
@ -114,7 +116,7 @@ public:
* Is whitespace stripping allowed for the given node?
* See http://www.w3.org/TR/xslt#strip
*/
virtual MBool isStripSpaceAllowed(Node* aNode) = 0;
virtual MBool isStripSpaceAllowed(const txXPathNode& aNode) = 0;
/**
* Returns a pointer to the private context
@ -132,7 +134,7 @@ public:
#define TX_DECL_MATCH_CONTEXT \
nsresult getVariable(PRInt32 aNamespace, nsIAtom* aLName, \
txAExprResult*& aResult); \
MBool isStripSpaceAllowed(Node* aNode); \
MBool isStripSpaceAllowed(const txXPathNode& aNode); \
void* getPrivateContext(); \
txResultRecycler* recycler(); \
void receiveError(const nsAString& aMsg, nsresult aRes)
@ -147,7 +149,7 @@ public:
/*
* Get the context node.
*/
virtual Node* getContextNode() = 0;
virtual const txXPathNode& getContextNode() = 0;
/*
* Get the size of the context node set.
@ -163,7 +165,7 @@ public:
#define TX_DECL_EVAL_CONTEXT \
TX_DECL_MATCH_CONTEXT; \
Node* getContextNode(); \
const txXPathNode& getContextNode(); \
PRUint32 size(); \
PRUint32 position()

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

@ -53,75 +53,92 @@ LocationStep::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
nsresult rv = aContext->recycler()->getNodeSet(getter_AddRefs(nodes));
NS_ENSURE_SUCCESS(rv, rv);
MBool reverse = MB_FALSE;
txXPathTreeWalker walker(aContext->getContextNode());
Node* node = aContext->getContextNode();
switch (mAxisIdentifier) {
case ANCESTOR_AXIS :
node = node->getXPathParent();
//-- do not break here
case ANCESTOR_OR_SELF_AXIS :
reverse = MB_TRUE;
while (node) {
if (mNodeTest->matches(node, aContext)) {
nodes->append(node);
}
node = node->getXPathParent();
}
break;
case ATTRIBUTE_AXIS :
case ANCESTOR_AXIS:
{
NamedNodeMap* atts = node->getAttributes();
if (atts) {
for (PRUint32 i = 0; i < atts->getLength(); i++) {
Node* attr = atts->item(i);
if (attr->getNamespaceID() != kNameSpaceID_XMLNS &&
mNodeTest->matches(attr, aContext))
nodes->append(attr);
if (!walker.moveToParent()) {
break;
}
// do not break here
}
case ANCESTOR_OR_SELF_AXIS:
{
nodes->setReverse();
do {
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
nodes->append(walker.getCurrentPosition());
}
} while (walker.moveToParent());
break;
}
case ATTRIBUTE_AXIS:
{
if (!walker.moveToFirstAttribute()) {
break;
}
do {
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
nodes->append(walker.getCurrentPosition());
}
} while (walker.moveToNextAttribute());
break;
}
case DESCENDANT_OR_SELF_AXIS:
{
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
nodes->append(walker.getCurrentPosition());
}
// do not break here
}
case DESCENDANT_AXIS:
{
fromDescendants(walker.getCurrentPosition(), aContext, nodes);
break;
}
case FOLLOWING_AXIS:
{
if (walker.getNodeType() == txXPathNodeType::ATTRIBUTE_NODE) {
walker.moveToParent();
fromDescendants(walker.getCurrentPosition(), aContext, nodes);
}
PRBool cont = PR_TRUE;
while (!walker.moveToNextSibling()) {
if (!walker.moveToParent()) {
cont = PR_FALSE;
break;
}
}
while (cont) {
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
nodes->append(walker.getCurrentPosition());
}
fromDescendants(walker.getCurrentPosition(), aContext, nodes);
while (!walker.moveToNextSibling()) {
if (!walker.moveToParent()) {
cont = PR_FALSE;
break;
}
}
}
break;
}
case DESCENDANT_OR_SELF_AXIS :
if (mNodeTest->matches(node, aContext))
nodes->append(node);
//-- do not break here
case DESCENDANT_AXIS :
fromDescendants(node, aContext, nodes);
break;
case FOLLOWING_AXIS :
case FOLLOWING_SIBLING_AXIS:
{
if ( node->getNodeType() == Node::ATTRIBUTE_NODE) {
node = node->getXPathParent();
fromDescendants(node, aContext, nodes);
}
while (node && !node->getNextSibling()) {
node = node->getXPathParent();
}
while (node) {
node = node->getNextSibling();
if (mNodeTest->matches(node, aContext))
nodes->append(node);
if (node->hasChildNodes())
fromDescendants(node, aContext, nodes);
while (node && !node->getNextSibling()) {
node = node->getParentNode();
while (walker.moveToNextSibling()) {
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
nodes->append(walker.getCurrentPosition());
}
}
break;
}
case FOLLOWING_SIBLING_AXIS :
node = node->getNextSibling();
while (node) {
if (mNodeTest->matches(node, aContext))
nodes->append(node);
node = node->getNextSibling();
}
break;
case NAMESPACE_AXIS : //-- not yet implemented
case NAMESPACE_AXIS: //-- not yet implemented
#if 0
// XXX DEBUG OUTPUT
cout << "namespace axis not yet implemented"<<endl;
@ -129,106 +146,121 @@ LocationStep::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
break;
case PARENT_AXIS :
{
Node* parent = node->getXPathParent();
if (mNodeTest->matches(parent, aContext))
nodes->append(parent);
if (walker.moveToParent() &&
mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
nodes->append(walker.getCurrentPosition());
}
break;
}
case PRECEDING_AXIS :
reverse = MB_TRUE;
while (node && !node->getPreviousSibling()) {
node = node->getXPathParent();
case PRECEDING_AXIS:
{
nodes->setReverse();
PRBool cont = PR_TRUE;
while (!walker.moveToPreviousSibling()) {
if (!walker.moveToParent()) {
cont = PR_FALSE;
break;
}
}
while (node) {
node = node->getPreviousSibling();
while (cont) {
fromDescendantsRev(walker.getCurrentPosition(), aContext, nodes);
if (node->hasChildNodes())
fromDescendantsRev(node, aContext, nodes);
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
nodes->append(walker.getCurrentPosition());
}
if (mNodeTest->matches(node, aContext))
nodes->append(node);
while (node && !node->getPreviousSibling()) {
node = node->getParentNode();
while (!walker.moveToPreviousSibling()) {
if (!walker.moveToParent()) {
cont = PR_FALSE;
break;
}
}
}
break;
}
case PRECEDING_SIBLING_AXIS:
reverse = MB_TRUE;
node = node->getPreviousSibling();
while (node) {
if (mNodeTest->matches(node, aContext))
nodes->append(node);
node = node->getPreviousSibling();
}
break;
case SELF_AXIS :
if (mNodeTest->matches(node, aContext))
nodes->append(node);
break;
default: //-- Children Axis
{
node = node->getFirstChild();
while (node) {
if (mNodeTest->matches(node, aContext))
nodes->append(node);
node = node->getNextSibling();
nodes->setReverse();
while (walker.moveToPreviousSibling()) {
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
nodes->append(walker.getCurrentPosition());
}
}
break;
}
} //-- switch
case SELF_AXIS:
{
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
nodes->append(walker.getCurrentPosition());
}
break;
}
default: // Children Axis
{
if (!walker.moveToFirstChild()) {
break;
}
//-- apply predicates
do {
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
nodes->append(walker.getCurrentPosition());
}
} while (walker.moveToNextSibling());
break;
}
}
// Apply predicates
if (!isEmpty()) {
rv = evaluatePredicates(nodes, aContext);
NS_ENSURE_SUCCESS(rv, rv);
}
if (reverse)
nodes->reverse();
nodes->unsetReverse();
NS_ADDREF(*aResult = nodes);
return NS_OK;
}
void LocationStep::fromDescendants(Node* node,
txIMatchContext* cs,
txNodeSet* nodes)
void LocationStep::fromDescendants(const txXPathNode& aNode,
txIMatchContext* aCs,
txNodeSet* aNodes)
{
if (!node)
txXPathTreeWalker walker(aNode);
if (!walker.moveToFirstChild()) {
return;
Node* child = node->getFirstChild();
while (child) {
if (mNodeTest->matches(child, cs))
nodes->append(child);
//-- check childs descendants
if (child->hasChildNodes())
fromDescendants(child, cs, nodes);
child = child->getNextSibling();
}
do {
const txXPathNode& child = walker.getCurrentPosition();
if (mNodeTest->matches(child, aCs)) {
aNodes->append(child);
}
fromDescendants(child, aCs, aNodes);
} while (walker.moveToNextSibling());
}
void LocationStep::fromDescendantsRev(Node* node,
txIMatchContext* cs,
txNodeSet* nodes)
void LocationStep::fromDescendantsRev(const txXPathNode& aNode,
txIMatchContext* aCs,
txNodeSet* aNodes)
{
if (!node)
txXPathTreeWalker walker(aNode);
if (!walker.moveToLastChild()) {
return;
Node* child = node->getLastChild();
while (child) {
//-- check childs descendants
if (child->hasChildNodes())
fromDescendantsRev(child, cs, nodes);
if (mNodeTest->matches(child, cs))
nodes->append(child);
child = child->getPreviousSibling();
}
do {
const txXPathNode& child = walker.getCurrentPosition();
fromDescendantsRev(child, aCs, aNodes);
if (mNodeTest->matches(child, aCs)) {
aNodes->append(child);
}
} while (walker.moveToPreviousSibling());
}
/**

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

@ -25,10 +25,11 @@
#include "Expr.h"
#include "txAtoms.h"
#include "txXPathTreeWalker.h"
#include "txIXPathContext.h"
txNameTest::txNameTest(nsIAtom* aPrefix, nsIAtom* aLocalName, PRInt32 aNSID,
Node::NodeType aNodeType)
PRUint16 aNodeType)
:mPrefix(aPrefix), mLocalName(aLocalName), mNamespace(aNSID),
mNodeType(aNodeType)
{
@ -41,12 +42,9 @@ txNameTest::~txNameTest()
{
}
/*
* Determines whether this txNodeTest matches the given node
*/
MBool txNameTest::matches(Node* aNode, txIMatchContext* aContext)
PRBool txNameTest::matches(const txXPathNode& aNode, txIMatchContext* aContext)
{
if (!aNode || aNode->getNodeType() != mNodeType)
if (txXPathNodeUtils::getNodeType(aNode) != mNodeType)
return MB_FALSE;
// Totally wild?
@ -54,7 +52,7 @@ MBool txNameTest::matches(Node* aNode, txIMatchContext* aContext)
return MB_TRUE;
// Compare namespaces
if (aNode->getNamespaceID() != mNamespace)
if (txXPathNodeUtils::getNamespaceID(aNode) != mNamespace)
return MB_FALSE;
// Name wild?
@ -62,8 +60,7 @@ MBool txNameTest::matches(Node* aNode, txIMatchContext* aContext)
return MB_TRUE;
// Compare local-names
nsCOMPtr<nsIAtom> localName;
aNode->getLocalName(getter_AddRefs(localName));
nsCOMPtr<nsIAtom> localName = txXPathNodeUtils::getLocalName(aNode);
return localName == mLocalName;
}

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

@ -31,95 +31,133 @@
*/
#include "txNodeSet.h"
#include "dom.h"
#include "XMLDOMUtils.h"
#include <string.h>
#include "TxLog.h"
#include "nsMemory.h"
static const int kTxNodeSetMinSize = 4;
static const int kTxNodeSetGrowFactor = 2;
/*
* Implementation of an XPath NodeSet
/**
* Implementation of an XPath nodeset
*/
/*
* Creates a new empty NodeSet
*/
static const PRInt32 kTxNodeSetMinSize = 4;
static const PRInt32 kTxNodeSetGrowFactor = 2;
#define kForward 1
#define kReversed -1
txNodeSet::txNodeSet(txResultRecycler* aRecycler)
: txAExprResult(aRecycler),
mElements(0),
mBufferSize(0),
mElementCount(0)
mStart(nsnull),
mEnd(nsnull),
mStartBuffer(nsnull),
mEndBuffer(nsnull),
mDirection(kForward),
mMarks(nsnull)
{
}
/*
* Creates a new NodeSet containing the supplied Node
*/
txNodeSet::txNodeSet(Node* aNode, txResultRecycler* aRecycler)
txNodeSet::txNodeSet(const txXPathNode& aNode, txResultRecycler* aRecycler)
: txAExprResult(aRecycler),
mElements(new Node*[1]),
mBufferSize(1),
mElementCount(1)
mStart(nsnull),
mEnd(nsnull),
mStartBuffer(nsnull),
mEndBuffer(nsnull),
mDirection(kForward),
mMarks(nsnull)
{
NS_ASSERTION(aNode, "missing node to txNodeSet::txNodeSet");
if (!mElements) {
NS_ASSERTION(0, "out of memory");
mBufferSize = 0;
mElementCount = 0;
}
else {
mElements[0] = aNode;
if (!ensureGrowSize(1)) {
return;
}
new(mStart) txXPathNode(aNode);
++mEnd;
}
/*
* Creates a new NodeSet, copying the Node references from the source
* NodeSet
*/
txNodeSet::txNodeSet(const txNodeSet& aSource, txResultRecycler* aRecycler)
: txAExprResult(aRecycler),
mElements(0),
mBufferSize(0),
mElementCount(0)
mStart(nsnull),
mEnd(nsnull),
mStartBuffer(nsnull),
mEndBuffer(nsnull),
mDirection(kForward),
mMarks(nsnull)
{
append(&aSource);
append(aSource);
}
/*
* Adds the specified Node to this NodeSet if it is not already in this
* NodeSet. The node is inserted according to document order.
* @param aNode the Node to add to the NodeSet
* @return errorcode.
*/
nsresult txNodeSet::add(Node* aNode)
txNodeSet::~txNodeSet()
{
NS_ASSERTION(aNode, "missing node to txNodeSet::add");
if (!aNode)
return NS_ERROR_NULL_POINTER;
delete [] mMarks;
MBool nonDup;
int pos = findPosition(aNode, 0, mElementCount - 1, nonDup);
if (nonDup) {
if (!ensureSize(mElementCount + 1))
return NS_ERROR_OUT_OF_MEMORY;
memmove(mElements + pos + 1,
mElements + pos,
(mElementCount - pos) * sizeof(Node*));
mElements[pos] = aNode;
++mElementCount;
if (mStartBuffer) {
while (mStart < mEnd) {
mStart->~txXPathNode();
++mStart;
}
nsMemory::Free(mStartBuffer);
}
}
nsresult txNodeSet::add(const txXPathNode& aNode)
{
NS_ASSERTION(mDirection == kForward,
"only append(aNode) is supported on reversed nodesets");
if (isEmpty()) {
return append(aNode);
}
PRBool dupe;
txXPathNode* pos = findPosition(aNode, mStart, mEnd, dupe);
if (dupe) {
return NS_OK;
}
// save pos, ensureGrowSize messes with the pointers
PRInt32 moveSize = mEnd - pos;
PRInt32 offset = pos - mStart;
if (!ensureGrowSize(1)) {
return NS_ERROR_OUT_OF_MEMORY;
}
// set pos to where it was
pos = mStart + offset;
if (moveSize > 0) {
memmove(pos + 1, pos, moveSize * sizeof(txXPathNode));
}
new(pos) txXPathNode(aNode);
++mEnd;
return NS_OK;
}
/*
* Adds the nodes in specified NodeSet to this NodeSet. The resulting NodeSet
* is sorted in document order and does not contain any duplicate nodes.
* @param aNodes the NodeSet to add, must be in document order.
* @return true on success. false on failure.
*/
nsresult txNodeSet::add(const txNodeSet& aNodes)
{
return add(aNodes, copyElements);
}
/*
nsresult txNodeSet::addAndTransfer(txNodeSet* aNodes)
{
// failure is out-of-memory, transfer didn't happen
nsresult rv = add(*aNodes, transferElements);
NS_ENSURE_SUCCESS(rv, rv);
#ifdef TX_DONT_RECYCLE_BUFFER
if (aNodes->mStartBuffer) {
nsMemory::Free(aNodes->mStartBuffer);
aNodes->mStartBuffer = aNodes->mEndBuffer = nsnull;
}
#endif
aNodes->mStart = aNodes->mEnd = aNodes->mStartBuffer;
return NS_OK;
}
/**
* add(aNodeSet, aTransferOp)
*
* The code is optimized to make a minimum number of calls to
* Node::compareDocumentPosition. The idea is this:
* We have the two nodesets (number indicate "document position")
@ -129,267 +167,320 @@ nsresult txNodeSet::add(Node* aNode)
* _ _ _ _ _ _ _ _ <- result
*
*
* We select the last node in the smallest nodeset and find where in the other
* nodeset it would be inserted. In this case we would take the 7 from the
* first nodeset and find the position between the 6 and 8 in the second.
* We then take the nodes after the insert-position and move it to the end of
* the resulting nodeset, and then do the same for the node from the smaller
* nodeset. Which in this case means that we'd first move the 8 and 9 nodes,
* and then the 7 node, giving us the following:
* When merging these nodesets into the result, the nodes are transfered
* in chunks to the end of the buffer so that each chunk does not contain
* a node from the other nodeset, in document order.
*
* We select the last non-transfered node in the first nodeset and find
* where in the other nodeset it would be inserted. In this case we would
* take the 7 from the first nodeset and find the position between the
* 6 and 8 in the second. We then take the nodes after the insert-position
* and transfer them to the end of the resulting nodeset. Which in this case
* means that we first transfered the 8 and 9 nodes, giving us the following:
*
* 1 3 <- source 1
* 1 3 7 <- source 1
* 2 3 6 <- source 2
* _ _ _ _ _ 7 8 9 <- result
* _ _ _ _ _ _ 8 9 <- result
*
* The corresponding procedure is done for the second nodeset, that is
* the insertion position of the 6 in the first nodeset is found, which
* is between the 3 and the 7. The 7 is memmoved (as it stays within
* the same nodeset) to the result buffer.
*
* As the result buffer is filled from the end, it is safe to share the
* buffer between this nodeset and the result.
*
* Repeat until one of the nodesets are empty. If we find a duplicate node
* when searching for where insertposition we skip the step where we move the
* node from the smaller nodeset to the resulting nodeset. So in this next
* step in the example we would only move the 3 and 6 nodes from the second
* nodeset and then just remove the 3 node from the first nodeset. Giving:
*
* 1 <- source 1
* 2 <- source 2
* _ _ _ 3 6 7 8 9 <- result
*
* We might therefor end up with some blanks in the bigining of the resulting
* nodeset, which we simply fix by moving all the nodes one step down.
* This is repeated until both of the nodesets are empty.
*
* If we find a duplicate node when searching for where insertposition we
* check for sequences of duplicate nodes, which can be optimized.
*
*/
nsresult txNodeSet::add(const txNodeSet* aNodes)
nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer)
{
NS_ASSERTION(aNodes, "missing nodeset to txNodeSet::add");
if (!aNodes)
return NS_ERROR_NULL_POINTER;
NS_ASSERTION(mDirection == kForward,
"only append(aNode) is supported on reversed nodesets");
if (aNodes->mElementCount == 0)
if (aNodes.isEmpty()) {
return NS_OK;
}
// This is probably a rather common case, so lets try to shortcut
if (mElementCount == 0 ||
mElements[mElementCount-1]->compareDocumentPosition(aNodes->mElements[0]) < 0)
return append(aNodes);
if (!ensureSize(mElementCount + aNodes->mElementCount))
if (!ensureGrowSize(aNodes.size())) {
return NS_ERROR_OUT_OF_MEMORY;
}
// Index of last node in this nodeset
int thisPos = mElementCount - 1;
// Index of last node in other nodeset
int otherPos = aNodes->mElementCount - 1;
// Index in result where last insert was done.
int lastInsertPos = mElementCount + aNodes->mElementCount;
while (thisPos >= 0 && otherPos >= 0) {
if (thisPos > otherPos) {
int pos;
MBool nonDup;
// Find where in the remaining nodes in this nodeset a node from
// the other nodeset should be inserted
pos = findPosition(aNodes->mElements[otherPos], 0, thisPos,
nonDup);
// This is probably a rather common case, so lets try to shortcut.
if (mStart == mEnd ||
txXPathNodeUtils::comparePosition(mEnd[-1], *aNodes.mStart) < 0) {
aTransfer(mEnd, aNodes.mStart, aNodes.mEnd);
mEnd += aNodes.size();
// Move nodes in this nodeset
lastInsertPos -= thisPos - pos + 1;
memmove(mElements + lastInsertPos,
mElements + pos,
(thisPos - pos + 1) * sizeof(Node*));
return NS_OK;
}
// Copy node from the other nodeset unless it's a dup
if (nonDup)
mElements[--lastInsertPos] = aNodes->mElements[otherPos];
// Adjust positions in both nodesets
thisPos = pos - 1;
--otherPos;
// Last element in this nodeset
txXPathNode* thisPos = mEnd;
// Last element of the other nodeset
txXPathNode* otherPos = aNodes.mEnd;
// Pointer to the insertion point in this nodeset
txXPathNode* insertPos = mEndBuffer;
PRBool dupe;
txXPathNode* pos;
PRInt32 count;
while (thisPos > mStart || otherPos > aNodes.mStart) {
// Find where the last remaining node of this nodeset would
// be inserted in the other nodeset.
if (thisPos > mStart) {
pos = findPosition(thisPos[-1], aNodes.mStart, otherPos, dupe);
if (dupe) {
--thisPos; // this is already added
// check dupe sequence
while (thisPos > mStart && pos > aNodes.mStart &&
thisPos[-1] == pos[-1]) {
--thisPos;
--pos;
}
}
}
else {
int pos;
MBool nonDup;
// Find where in the remaining nodes in the other nodeset a node
// from this nodeset should be inserted
pos = aNodes->findPosition(mElements[thisPos], 0, otherPos,
nonDup);
pos = aNodes.mStart;
}
// Copy nodes from other nodeset to this
lastInsertPos -= otherPos - pos + 1;
memcpy(mElements + lastInsertPos,
aNodes->mElements + pos,
(otherPos - pos + 1) * sizeof(Node*));
// Transfer the otherNodes after the insertion point to the result
count = otherPos - pos;
if (count > 0) {
insertPos -= count;
aTransfer(insertPos, pos, otherPos);
otherPos -= count;
}
// Move node in this nodeset unless it's a dup
if (nonDup)
mElements[--lastInsertPos] = mElements[thisPos];
// Adjust positions in both nodesets
otherPos = pos - 1;
--thisPos;
// Find where the last remaining node of the otherNodeset would
// be inserted in this nodeset.
if (otherPos > aNodes.mStart) {
pos = findPosition(otherPos[-1], mStart, thisPos, dupe);
if (dupe) {
--otherPos; // this is already added
// check dupe sequence
while (otherPos > aNodes.mStart && pos > mStart &&
otherPos[-1] == pos[-1]) {
--otherPos;
--pos;
}
}
}
else {
pos = mStart;
}
// Move the nodes from this nodeset after the insertion point
// to the result
count = thisPos - pos;
if (count > 0) {
insertPos -= count;
memmove(insertPos, pos, count * sizeof(txXPathNode));
thisPos -= count;
}
}
mStart = insertPos;
mEnd = mEndBuffer;
if (thisPos >= 0) {
// There were some elements still left in this nodeset that need to
// be moved
lastInsertPos -= thisPos + 1;
memmove(mElements + lastInsertPos,
mElements,
(thisPos + 1) * sizeof(Node*));
}
else if (otherPos >= 0) {
// There were some elements still left in the other nodeset that need
// to be copied
lastInsertPos -= otherPos + 1;
memcpy(mElements + lastInsertPos,
aNodes->mElements,
(otherPos + 1) * sizeof(Node*));
}
// if lastInsertPos != 0 then we have found some duplicates causing the
// first element to not be placed at mElements[0]
mElementCount += aNodes->mElementCount - lastInsertPos;
if (lastInsertPos) {
memmove(mElements,
mElements + lastInsertPos,
mElementCount * sizeof(Node*));
}
return NS_OK;
}
/*
/**
* Append API
* These functions should be used with care.
* They are intended to be used when the caller assures that the resulting
* NodeSet remains in document order.
* nodeset remains in document order.
* Abuse will break document order, and cause errors in the result.
* These functions are significantly faster than the add API, as no
* Node::OrderInfo structs will be generated.
* order info operations will be performed.
*/
/*
* Appends the specified Node to the end of this NodeSet
* @param aNode the Node to append to the NodeSet
* @return true on success. false on failure.
*/
nsresult txNodeSet::append(Node* aNode)
nsresult
txNodeSet::append(const txXPathNode& aNode)
{
NS_ASSERTION(aNode, "missing node to txNodeSet::append");
if (!aNode)
return NS_ERROR_NULL_POINTER;
if (!ensureSize(mElementCount + 1))
if (!ensureGrowSize(1)) {
return NS_ERROR_OUT_OF_MEMORY;
}
mElements[mElementCount++] = aNode;
if (mDirection == kForward) {
new(mEnd) txXPathNode(aNode);
++mEnd;
return NS_OK;
}
new(--mStart) txXPathNode(aNode);
return NS_OK;
}
/*
* Appends the nodes in the specified NodeSet to the end of this NodeSet
* @param aNodes the NodeSet to append to the NodeSet
* @return true on success. false on failure.
*/
nsresult txNodeSet::append(const txNodeSet* aNodes)
nsresult
txNodeSet::append(const txNodeSet& aNodes)
{
NS_ASSERTION(aNodes, "missing nodeset to txNodeSet::append");
if (!aNodes)
return NS_ERROR_NULL_POINTER;
NS_ASSERTION(mDirection == kForward,
"only append(aNode) is supported on reversed nodesets");
if (!ensureSize(mElementCount + aNodes->mElementCount))
if (aNodes.isEmpty()) {
return NS_OK;
}
PRInt32 appended = aNodes.size();
if (!ensureGrowSize(appended)) {
return NS_ERROR_OUT_OF_MEMORY;
}
memcpy(mElements + mElementCount,
aNodes->mElements,
aNodes->mElementCount * sizeof(Node*));
mElementCount += aNodes->mElementCount;
copyElements(mEnd, aNodes.mStart, aNodes.mEnd);
mEnd += appended;
return NS_OK;
}
/*
* Reverse the order of the nodes.
*/
void txNodeSet::reverse()
nsresult
txNodeSet::mark(PRInt32 aIndex)
{
int i;
for (i = 0; i < mElementCount / 2; ++i) {
Node* tmp;
tmp = mElements[i];
mElements[i] = mElements[mElementCount - 1 - i];
mElements[mElementCount - 1 - i] = tmp;
NS_ASSERTION(aIndex >= 0 && mStart && mEnd - mStart > aIndex,
"index out of bounds");
if (!mMarks) {
PRInt32 length = size();
mMarks = new PRPackedBool[length];
NS_ENSURE_TRUE(mMarks, NS_ERROR_OUT_OF_MEMORY);
memset(mMarks, 0, length * sizeof(PRPackedBool));
}
if (mDirection == kForward) {
mMarks[aIndex] = PR_TRUE;
}
else {
mMarks[size() - aIndex - 1] = PR_TRUE;
}
return NS_OK;
}
/*
* Returns the index of the specified Node,
* or -1 if the Node is not contained in the NodeSet
* @param aNode the Node to get the index for
* @return index of specified node or -1 if the node does not exist
*/
int txNodeSet::indexOf(Node* aNode) const
nsresult
txNodeSet::sweep()
{
// XXX this doesn't fully work since attribute-nodes are broken
// and can't be pointer-compared. However it's the best we can
// do for now.
int i;
for (i = 0; i < mElementCount; ++i) {
if (mElements[i] == aNode)
return i;
if (!mMarks) {
// sweep everything
clear();
}
PRInt32 chunk, pos = 0;
PRInt32 length = size();
txXPathNode* insertion = mStartBuffer;
while (pos < length) {
while (pos < length && !mMarks[pos]) {
// delete unmarked
mStart[pos].~txXPathNode();
++pos;
}
// find chunk to move
chunk = 0;
while (pos < length && mMarks[pos]) {
++pos;
++chunk;
}
// move chunk
if (chunk > 0) {
memmove(insertion, mStart + pos - chunk,
chunk * sizeof(txXPathNode));
insertion += chunk;
}
}
mStart = mStartBuffer;
mEnd = insertion;
delete [] mMarks;
mMarks = nsnull;
return NS_OK;
}
void
txNodeSet::clear()
{
while (mStart < mEnd) {
mStart->~txXPathNode();
++mStart;
}
#ifdef TX_DONT_RECYCLE_BUFFER
if (mStartBuffer) {
nsMemory::Free(mStartBuffer);
mStartBuffer = mEndBuffer = nsnull;
}
#endif
mStart = mEnd = mStartBuffer;
delete [] mMarks;
mMarks = nsnull;
mDirection = kForward;
}
PRInt32
txNodeSet::indexOf(const txXPathNode& aNode) const
{
NS_ASSERTION(mDirection == kForward,
"only append(aNode) is supported on reversed nodesets");
if (!mStart || mStart == mEnd) {
return -1;
}
PRInt32 counter = 0;
txXPathNode* pos = mStart;
for (; pos < mEnd; ++counter, ++pos) {
if (*pos == aNode) {
return counter;
}
}
return -1;
}
/*
* Returns the Node at the specified position in this NodeSet.
* @param aIndex the position of the Node to return
* @return Node at specified position
*/
Node* txNodeSet::get(int aIndex) const
const txXPathNode&
txNodeSet::get(PRInt32 aIndex) const
{
NS_ASSERTION(aIndex >= 0 && aIndex < mElementCount,
"invalid index in txNodeSet::get");
if (aIndex < 0 || aIndex >= mElementCount)
return 0;
if (mDirection == kForward) {
return mStart[aIndex];
}
return mElements[aIndex];
return mEnd[-aIndex - 1];
}
/*
* Returns the type of ExprResult represented
* @return the type of ExprResult represented
*/
short txNodeSet::getResultType()
short
txNodeSet::getResultType()
{
return txAExprResult::NODESET;
}
/*
* Converts this ExprResult to a Boolean (MBool) value
* @return the Boolean value
*/
MBool txNodeSet::booleanValue()
PRBool
txNodeSet::booleanValue()
{
return mElementCount > 0;
return !isEmpty();
}
/*
* Converts this ExprResult to a Number (double) value
* @return the Number value
*/
double txNodeSet::numberValue()
double
txNodeSet::numberValue()
{
nsAutoString str;
stringValue(str);
return Double::toDouble(str);
}
/*
* Creates a String representation of this ExprResult
* @param aStr the destination string to append the String representation to.
*/
void txNodeSet::stringValue(nsAString& aStr)
void
txNodeSet::stringValue(nsAString& aStr)
{
if (mElementCount > 0)
XMLDOMUtils::getNodeValue(get(0), aStr);
NS_ASSERTION(mDirection == kForward,
"only append(aNode) is supported on reversed nodesets");
if (isEmpty()) {
return;
}
txXPathNodeUtils::appendNodeValue(get(0), aStr);
}
nsAString*
@ -398,89 +489,132 @@ txNodeSet::stringValuePointer()
return nsnull;
}
/*
* Makes sure that the mElements buffer contains at least aSize elements.
* If a new allocation is required the elements are copied over to the new
* buffer
* @param aSize requested number of elements
* @return true if allocation succeded, false on out of memory
*/
MBool txNodeSet::ensureSize(int aSize)
PRBool txNodeSet::ensureGrowSize(PRInt32 aSize)
{
if (aSize <= mBufferSize)
return MB_TRUE;
// check if there is enough place in the buffer as is
if (mDirection == kForward && aSize <= mEndBuffer - mEnd) {
return PR_TRUE;
}
if (mDirection == kReversed && aSize <= mStart - mStartBuffer) {
return PR_TRUE;
}
// check if we just have to align mStart to have enough space
PRInt32 oldSize = mEnd - mStart;
PRInt32 oldLength = mEndBuffer - mStartBuffer;
PRInt32 ensureSize = oldSize + aSize;
if (ensureSize <= oldLength) {
// just move the buffer
txXPathNode* dest = mStartBuffer;
if (mDirection == kReversed) {
dest = mEndBuffer - oldSize;
}
memmove(dest, mStart, oldSize * sizeof(txXPathNode));
mStart = dest;
mEnd = dest + oldSize;
return PR_TRUE;
}
// This isn't 100% safe. But until someone manages to make a 1gig nodeset
// it should be ok.
int newSize = mBufferSize > kTxNodeSetMinSize ? mBufferSize :
kTxNodeSetMinSize;
while (newSize < aSize)
newSize *= kTxNodeSetGrowFactor;
PRInt32 newLength = PR_MAX(oldLength, kTxNodeSetMinSize);
Node** newArr = new Node*[newSize];
if (!newArr)
return MB_FALSE;
if (mElementCount)
memcpy(newArr, mElements, mElementCount * sizeof(Node*));
while (newLength < ensureSize) {
newLength *= kTxNodeSetGrowFactor;
}
delete [] mElements;
mElements = newArr;
mBufferSize = newSize;
return MB_TRUE;
txXPathNode* newArr = NS_STATIC_CAST(txXPathNode*,
nsMemory::Alloc(newLength *
sizeof(txXPathNode)));
if (!newArr) {
return PR_FALSE;
}
txXPathNode* dest = newArr;
if (mDirection == kReversed) {
dest += newLength - oldSize;
}
if (oldSize > 0) {
memcpy(dest, mStart, oldSize * sizeof(txXPathNode));
}
if (mStartBuffer) {
#ifdef DEBUG
memset(mStartBuffer, 0,
(mEndBuffer - mStartBuffer) * sizeof(txXPathNode));
#endif
nsMemory::Free(mStartBuffer);
}
mStartBuffer = newArr;
mEndBuffer = mStartBuffer + newLength;
mStart = dest;
mEnd = dest + oldSize;
return PR_TRUE;
}
/*
* Finds position in the mElements buffer where a node should be inserted
* to keep the nodeset in document order. Searches the positions
* aFirst-aLast, including both aFirst and aLast.
* @param aNode Node to find insert position for
* @param aFirst First index to search, this index will be searched
* @param aLast Last index to search, this index will be searched
* @param aNonDup Out-param. Set to true if the node should be inserted,
* false if it already exists in the NodeSet.
* @return The index where to insert the node. The node should be
* inserted before the node at this index. This value is
* always >= aFirst and <= aLast + 1. This value is always
* set, even if aNode already exists in the NodeSet
*/
int txNodeSet::findPosition(Node* aNode, int aFirst,
int aLast, MBool& aNonDup) const
txXPathNode*
txNodeSet::findPosition(const txXPathNode& aNode, txXPathNode* aFirst,
txXPathNode* aLast, PRBool& aDupe) const
{
NS_ASSERTION(aNode, "missing node in txNodeSet::findPosition");
NS_ASSERTION(aFirst <= aLast+1 && aLast < mElementCount,
"bad position in txNodeSet::findPosition");
if (aLast - aFirst <= 1) {
aDupe = PR_FALSE;
if (aLast - aFirst <= 2) {
// If we search 2 nodes or less there is no point in further divides
int pos;
for (pos = aFirst; pos <= aLast; ++pos) {
int cmp = aNode->compareDocumentPosition(mElements[pos]);
txXPathNode* pos = aFirst;
for (; pos < aLast; ++pos) {
PRIntn cmp = txXPathNodeUtils::comparePosition(aNode, *pos);
if (cmp < 0) {
aNonDup = MB_TRUE;
return pos;
}
if (cmp == 0) {
aNonDup = MB_FALSE;
aDupe = PR_TRUE;
return pos;
}
}
aNonDup = MB_TRUE;
return pos;
}
int midpos = (aFirst + aLast) / 2;
int cmp = aNode->compareDocumentPosition(mElements[midpos]);
// (cannot add two pointers)
txXPathNode* midpos = aFirst + (aLast - aFirst) / 2;
PRIntn cmp = txXPathNodeUtils::comparePosition(aNode, *midpos);
if (cmp == 0) {
aNonDup = MB_FALSE;
aDupe = PR_TRUE;
return midpos;
}
if (cmp > 0)
return findPosition(aNode, midpos + 1, aLast, aNonDup);
if (cmp > 0) {
return findPosition(aNode, midpos + 1, aLast, aDupe);
}
return findPosition(aNode, aFirst, midpos - 1, aNonDup);
// midpos excluded as end of range
return findPosition(aNode, aFirst, midpos, aDupe);
}
/* static */
void
txNodeSet::copyElements(txXPathNode* aDest,
const txXPathNode* aStart, const txXPathNode* aEnd)
{
const txXPathNode* pos = aStart;
while (pos < aEnd) {
new(aDest) txXPathNode(*pos);
++aDest;
++pos;
}
}
/* static */
void
txNodeSet::transferElements(txXPathNode* aDest,
const txXPathNode* aStart, const txXPathNode* aEnd)
{
memcpy(aDest, aStart, (aEnd - aStart) * sizeof(txXPathNode));
}

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

@ -27,183 +27,209 @@
*
*/
/*
/**
* Implementation of an XPath NodeSet
*/
#ifndef TRANSFRMX_NODESET_H
#define TRANSFRMX_NODESET_H
#ifndef txNodeSet_h__
#define txNodeSet_h__
#include "ExprResult.h"
#include "nsVoidArray.h"
#include "txError.h"
class Node;
#include "txXPathTreeWalker.h"
class txNodeSet : public txAExprResult
{
public:
// XXX TEMP
txNodeSet();
txNodeSet(); // Not to be implemented
/*
/**
* Creates a new empty NodeSet
*/
txNodeSet(txResultRecycler* aRecycler);
/*
* Creates a new NodeSet containing the supplied node
/**
* Creates a new NodeSet with one node.
*/
txNodeSet(Node* aNode, txResultRecycler* aRecycler);
txNodeSet(const txXPathNode& aNode, txResultRecycler* aRecycler);
/*
* Creates a new NodeSet, copying the Node references from the source
* NodeSet
/**
* Creates a new txNodeSet, copying the node references from the source
* NodeSet.
*/
txNodeSet(const txNodeSet& aSource, txResultRecycler* aRecycler);
/*
* Destructor for NodeSet, will not delete referenced Nodes
/**
* Destructor for txNodeSet, deletes the nodes.
*/
virtual ~txNodeSet()
{
delete [] mElements;
}
virtual ~txNodeSet();
/*
* Adds the specified Node to this NodeSet if it is not already in this
* NodeSet. The node is inserted according to document order.
* @param aNode the Node to add to the NodeSet
/**
* Adds the specified txXPathNode to this NodeSet if it is not already
* in this NodeSet. The node is inserted according to document order.
*
* @param aNode the txXPathNode to add to the NodeSet
* @return errorcode.
*/
nsresult add(Node* aNode);
nsresult add(const txXPathNode& aNode);
/*
/**
* Adds the nodes in specified NodeSet to this NodeSet. The resulting
* NodeSet is sorted in document order and does not contain any duplicate
* nodes.
*
* @param aNodes the NodeSet to add, must be in document order.
* @return errorcode.
*/
nsresult add(const txNodeSet* aNodes);
nsresult add(const txNodeSet& aNodes);
nsresult addAndTransfer(txNodeSet* aNodes);
/*
/**
* Append API
* These functions should be used with care.
* They are intended to be used when the caller assures that the resulting
* NodeSet remains in document order.
* Abuse will break document order, and cause errors in the result.
* These functions are significantly faster than the add API, as no
* Node::OrderInfo structs will be generated.
* order info operations will be performed.
*/
/*
/**
* Appends the specified Node to the end of this NodeSet
* @param aNode the Node to append to the NodeSet
* @return errorcode.
*/
nsresult append(Node* aNode);
nsresult append(const txXPathNode& aNode);
/*
/**
* Appends the nodes in the specified NodeSet to the end of this NodeSet
* @param aNodes the NodeSet to append to the NodeSet
* @return errorcode.
*/
nsresult append(const txNodeSet* aNodes);
nsresult append(const txNodeSet& aNodes);
/*
* Reverse the order of the nodes.
/**
* API to implement reverse axes in LocationStep.
*
* Before adding nodes to the nodeset for a reversed axis, call
* setReverse(). This will make the append(aNode) and get() methods treat
* the nodeset as required. Do only call append(aNode), get(), mark()
* and sweep() while the nodeset is reversed.
* Afterwards, call unsetReverse(). The nodes are stored in document
* order internally.
*/
void reverse();
/*
* Removes all nodes from this nodeset
*/
void clear()
void setReverse()
{
mElementCount = 0;
mDirection = -1;
}
void unsetReverse()
{
mDirection = 1;
}
/*
/**
* API to implement predicates in PredicateExpr
*
* mark(aIndex) marks the specified member of the nodeset.
* sweep() clears all members of the nodeset that haven't been
* marked before and clear the mMarks array.
*/
nsresult mark(PRInt32 aIndex);
nsresult sweep();
/**
* Removes all nodes from this nodeset
*/
void clear();
/**
* Returns the index of the specified Node,
* or -1 if the Node is not contained in the NodeSet
* @param aNode the Node to get the index for
* @return index of specified node or -1 if the node does not exist
*/
int indexOf(Node* aNode) const;
PRInt32 indexOf(const txXPathNode& aNode) const;
/*
/**
* Returns true if the specified Node is contained in the set.
* @param aNode the Node to search for
* @return true if specified Node is contained in the NodeSet
*/
MBool contains(Node* aNode) const
PRBool contains(const txXPathNode& aNode) const
{
return indexOf(aNode) >= 0;
}
/*
* Returns the Node at the specified position in this NodeSet.
* @param aIndex the position of the Node to return
* @return Node at specified position
/**
* Returns the Node at the specified node in this NodeSet.
* @param aIndex the node of the Node to return
* @return Node at specified node
*/
Node* get(int aIndex) const;
const txXPathNode& get(PRInt32 aIndex) const;
/*
/**
* Returns true if there are no Nodes in the NodeSet.
* @return true if there are no Nodes in the NodeSet.
*/
MBool isEmpty() const
PRBool isEmpty() const
{
return mElementCount == 0;
return mStart ? mStart == mEnd : PR_TRUE;
}
/*
/**
* Returns the number of elements in the NodeSet
* @return the number of elements in the NodeSet
*/
int size() const
PRInt32 size() const
{
return mElementCount;
return mStart ? mEnd - mStart : 0;
}
/*
* Virtual methods from ExprResult
*/
TX_DECL_EXPRRESULT
private:
static void toString(const txNodeSet& aNodes, nsAString& aResult);
/*
* Makes sure that the mElements buffer contains at least aSize elements.
* If a new allocation is required the elements are copied over to the new
* buffer
* @param aSize requested number of elements
* @return true if allocation succeded, false on out of memory
/**
* Ensure that this nodeset can take another aSize nodes.
*
* Changes mStart and mEnd as well as mBufferStart and mBufferEnd.
*/
MBool ensureSize(int aSize);
PRBool ensureGrowSize(PRInt32 aSize);
/*
* Finds position in the mElements buffer where a node should be inserted
/**
* Finds position in the buffer where a node should be inserted
* to keep the nodeset in document order. Searches the positions
* aFirst-aLast, including both aFirst and aLast.
* @param aNode Node to find insert position for
* @param aFirst First index to search, this index will be searched
* @param aLast Last index to search, this index will be searched
* @param aPos out-param. Will be set to the index where to insert the
* node. The node should be inserted before the node at
* this index. This value is always >= aFirst and
* <= aLast + 1. This value is always set, even if aNode
* already exists in the NodeSet.
* @return true if the node should be inserted, false if it already exists
* in the NodeSet
* aFirst-aLast, including aFirst, but not aLast.
* @param aNode Node to find insert position for.
* @param aFirst First item of the search range, included.
* @param aLast Last item of the search range, excluded.
* @param aDupe out-param. Will be set to true if the node already
* exists in the NodeSet, false if it should be
* inserted.
* @return pointer where to insert the node. The node should be inserted
* before the given node. This value is always set, even if aNode
* already exists in the NodeSet
*/
MBool findPosition(Node* aNode, int aFirst, int aLast, int& aPos) const;
txXPathNode* findPosition(const txXPathNode& aNode,
txXPathNode* aFirst,
txXPathNode* aLast, PRBool& aDupe) const;
Node** mElements;
int mBufferSize;
int mElementCount;
static void copyElements(txXPathNode* aDest, const txXPathNode* aStart,
const txXPathNode* aEnd);
static void transferElements(txXPathNode* aDest, const txXPathNode* aStart,
const txXPathNode* aEnd);
typedef void (*transferOp) (txXPathNode* aDest, const txXPathNode* aStart,
const txXPathNode* aEnd);
nsresult add(const txNodeSet& aNodes, transferOp aTransfer);
txXPathNode *mStart, *mEnd, *mStartBuffer, *mEndBuffer;
PRInt32 mDirection;
// used for mark() and sweep() in predicates
PRPackedBool* mMarks;
};
#endif

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

@ -39,7 +39,7 @@
#include "txNodeSetContext.h"
#include "txNodeSet.h"
Node* txNodeSetContext::getContextNode()
const txXPathNode& txNodeSetContext::getContextNode()
{
return mContextSet->get(mPosition - 1);
}
@ -62,7 +62,7 @@ nsresult txNodeSetContext::getVariable(PRInt32 aNamespace, nsIAtom* aLName,
return mInner->getVariable(aNamespace, aLName, aResult);
}
MBool txNodeSetContext::isStripSpaceAllowed(Node* aNode)
MBool txNodeSetContext::isStripSpaceAllowed(const txXPathNode& aNode)
{
NS_ASSERTION(mInner, "mInner is null!!!");
return mInner->isStripSpaceAllowed(aNode);

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

@ -33,11 +33,11 @@
*/
#include "FunctionLib.h"
#include "nsAutoPtr.h"
#include "txNodeSet.h"
#include "txAtoms.h"
#include "txIXPathContext.h"
#include "txTokenizer.h"
#include "XMLDOMUtils.h"
#ifndef TX_EXE
#include "nsIDOMNode.h"
#endif
@ -92,12 +92,7 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
NS_ENSURE_SUCCESS(rv, rv);
Document* contextDoc = 0;
Node* contextNode = aContext->getContextNode();
if (contextNode->getNodeType() == Node::DOCUMENT_NODE)
contextDoc = (Document*)contextNode;
else
contextDoc = contextNode->getOwnerDocument();
txXPathTreeWalker walker(aContext->getContextNode());
if (exprResult->getResultType() == txAExprResult::NODESET) {
txNodeSet* nodes = NS_STATIC_CAST(txNodeSet*,
@ -106,13 +101,12 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
PRInt32 i;
for (i = 0; i < nodes->size(); ++i) {
nsAutoString idList;
XMLDOMUtils::getNodeValue(nodes->get(i), idList);
txXPathNodeUtils::appendNodeValue(nodes->get(i), idList);
txTokenizer tokenizer(idList);
while (tokenizer.hasMoreTokens()) {
Node* idNode =
contextDoc->getElementById(tokenizer.nextToken());
if (idNode)
resultSet->add(idNode);
if (walker.moveToElementById(tokenizer.nextToken())) {
resultSet->add(walker.getCurrentPosition());
}
}
}
}
@ -121,10 +115,9 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
exprResult->stringValue(idList);
txTokenizer tokenizer(idList);
while (tokenizer.hasMoreTokens()) {
Node* idNode =
contextDoc->getElementById(tokenizer.nextToken());
if (idNode)
resultSet->add(idNode);
if (walker.moveToElementById(tokenizer.nextToken())) {
resultSet->add(walker.getCurrentPosition());
}
}
}
@ -149,10 +142,9 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
}
Node* node = 0;
// Check for optional arg
nsRefPtr<txNodeSet> nodes;
if (iter.hasNext()) {
nsRefPtr<txNodeSet> nodes;
rv = evaluateToNodeSet((Expr*)iter.next(), aContext,
getter_AddRefs(nodes));
NS_ENSURE_SUCCESS(rv, rv);
@ -162,12 +154,10 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return NS_OK;
}
node = nodes->get(0);
}
else {
node = aContext->getContextNode();
}
const txXPathNode& node = nodes ? nodes->get(0) :
aContext->getContextNode();
switch (mType) {
case LOCAL_NAME:
{
@ -176,23 +166,8 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
NS_ENSURE_SUCCESS(rv, rv);
*aResult = strRes;
#ifdef TX_EXE
nsCOMPtr<nsIAtom> localNameAtom;
node->getLocalName(getter_AddRefs(localNameAtom));
if (localNameAtom) {
// Node has a localName
localNameAtom->ToString(strRes->mValue);
}
#else
// The mozilla HTML-elements returns different casing for
// the localName-atom and .localName. Once we have a
// treeWalker it should have a getLocalName(nsAString&)
// function.
nsCOMPtr<nsIDOMNode> mozNode =
do_QueryInterface(node->getNSObj());
NS_ASSERTION(mozNode, "wrapper doesn't wrap a nsIDOMNode");
mozNode->GetLocalName(strRes->mValue);
#endif
txXPathNodeUtils::getLocalName(node, strRes->mValue);
return NS_OK;
}
case NAMESPACE_URI:
@ -202,16 +177,16 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
NS_ENSURE_SUCCESS(rv, rv);
*aResult = strRes;
node->getNamespaceURI(strRes->mValue);
txXPathNodeUtils::getNamespaceURI(node, strRes->mValue);
return NS_OK;
}
case NAME:
{
switch (node->getNodeType()) {
case Node::ATTRIBUTE_NODE:
case Node::ELEMENT_NODE:
case Node::PROCESSING_INSTRUCTION_NODE:
switch (txXPathNodeUtils::getNodeType(node)) {
case txXPathNodeType::ATTRIBUTE_NODE:
case txXPathNodeType::ELEMENT_NODE:
case txXPathNodeType::PROCESSING_INSTRUCTION_NODE:
// XXX Namespace: namespaces have a name
{
StringResult* strRes = nsnull;
@ -219,7 +194,7 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
NS_ENSURE_SUCCESS(rv, rv);
*aResult = strRes;
node->getNodeName(strRes->mValue);
txXPathNodeUtils::getNodeName(node, strRes->mValue);
return NS_OK;
}

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

@ -26,6 +26,7 @@
#include "Expr.h"
#include "nsIAtom.h"
#include "txIXPathContext.h"
#include "txXPathTreeWalker.h"
/*
* Creates a new txNodeTypeTest of the given type
@ -44,34 +45,29 @@ void txNodeTypeTest::setNodeName(const nsAString& aName)
mNodeName = do_GetAtom(aName);
}
/*
* Determines whether this txNodeTest matches the given node
*/
MBool txNodeTypeTest::matches(Node* aNode, txIMatchContext* aContext)
PRBool txNodeTypeTest::matches(const txXPathNode& aNode,
txIMatchContext* aContext)
{
if (!aNode)
return MB_FALSE;
Node::NodeType type = (Node::NodeType)aNode->getNodeType();
PRUint16 type = txXPathNodeUtils::getNodeType(aNode);
switch (mNodeType) {
case COMMENT_TYPE:
return type == Node::COMMENT_NODE;
return type == txXPathNodeType::COMMENT_NODE;
case TEXT_TYPE:
return (type == Node::TEXT_NODE ||
type == Node::CDATA_SECTION_NODE) &&
return (type == txXPathNodeType::TEXT_NODE ||
type == txXPathNodeType::CDATA_SECTION_NODE) &&
!aContext->isStripSpaceAllowed(aNode);
case PI_TYPE:
if (type == Node::PROCESSING_INSTRUCTION_NODE) {
if (type == txXPathNodeType::PROCESSING_INSTRUCTION_NODE) {
nsCOMPtr<nsIAtom> localName;
return !mNodeName ||
(aNode->getLocalName(getter_AddRefs(localName)) &&
((localName = txXPathNodeUtils::getLocalName(aNode)) &&
localName == mNodeName);
}
return MB_FALSE;
case NODE_TYPE:
return ((type != Node::TEXT_NODE &&
type != Node::CDATA_SECTION_NODE) ||
return ((type != txXPathNodeType::TEXT_NODE &&
type != txXPathNodeType::CDATA_SECTION_NODE) ||
!aContext->isStripSpaceAllowed(aNode));
}
return MB_TRUE;

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

@ -38,7 +38,6 @@
#include "txNodeSet.h"
#include "txAtoms.h"
#include "txIXPathContext.h"
#include "XMLDOMUtils.h"
/*
* Creates a NumberFunctionCall of the given type
@ -121,7 +120,7 @@ NumberFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
PRInt32 i;
for (i = 0; i < nodes->size(); ++i) {
nsAutoString resultStr;
XMLDOMUtils::getNodeValue(nodes->get(i), resultStr);
txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr);
res += Double::toDouble(resultStr);
}
return aContext->recycler()->getNumberResult(res, aResult);
@ -134,8 +133,8 @@ NumberFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
}
else {
nsAutoString resultStr;
XMLDOMUtils::getNodeValue(aContext->getContextNode(),
resultStr);
txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
resultStr);
res = Double::toDouble(resultStr);
}
return aContext->recycler()->getNumberResult(res, aResult);

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

@ -109,14 +109,14 @@ PathExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
txNodeSetContext eContext(nodes, aContext);
while (eContext.hasNext()) {
eContext.next();
Node* node = eContext.getContextNode();
nsRefPtr<txNodeSet> resNodes;
if (pxi->pathOp == DESCENDANT_OP) {
rv = aContext->recycler()->getNodeSet(getter_AddRefs(resNodes));
NS_ENSURE_SUCCESS(rv, rv);
rv = evalDescendants(pxi->expr, node, &eContext, resNodes);
rv = evalDescendants(pxi->expr, eContext.getContextNode(),
&eContext, resNodes);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
@ -141,7 +141,12 @@ PathExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
getNonSharedNodeSet(oldSet, getter_AddRefs(tmpNodes));
NS_ENSURE_SUCCESS(rv, rv);
tmpNodes->add(resNodes);
oldSet.swap(resNodes);
rv = aContext->recycler()->
getNonSharedNodeSet(oldSet, getter_AddRefs(resNodes));
NS_ENSURE_SUCCESS(rv, rv);
tmpNodes->addAndTransfer(resNodes);
}
}
else {
@ -165,8 +170,8 @@ PathExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
* all nodes that match the Expr
**/
nsresult
PathExpr::evalDescendants(Expr* aStep, Node* aNode, txIMatchContext* aContext,
txNodeSet* resNodes)
PathExpr::evalDescendants(Expr* aStep, const txXPathNode& aNode,
txIMatchContext* aContext, txNodeSet* resNodes)
{
txSingleNodeContext eContext(aNode, aContext);
nsRefPtr<txAExprResult> res;
@ -177,23 +182,34 @@ PathExpr::evalDescendants(Expr* aStep, Node* aNode, txIMatchContext* aContext,
//XXX ErrorReport: report nonnodeset error
return NS_ERROR_XSLT_NODESET_EXPECTED;
}
resNodes->add(NS_STATIC_CAST(txNodeSet*, NS_STATIC_CAST(txAExprResult*,
res)));
txNodeSet* oldSet = NS_STATIC_CAST(txNodeSet*,
NS_STATIC_CAST(txAExprResult*, res));
nsRefPtr<txNodeSet> newSet;
rv = aContext->recycler()->getNonSharedNodeSet(oldSet,
getter_AddRefs(newSet));
NS_ENSURE_SUCCESS(rv, rv);
resNodes->addAndTransfer(newSet);
MBool filterWS = aContext->isStripSpaceAllowed(aNode);
Node* child = aNode->getFirstChild();
while (child) {
txXPathTreeWalker walker(aNode);
if (!walker.moveToFirstChild()) {
return NS_OK;
}
do {
if (!(filterWS &&
(child->getNodeType() == Node::TEXT_NODE ||
child->getNodeType() == Node::CDATA_SECTION_NODE) &&
XMLUtils::isWhitespace(child))) {
rv = evalDescendants(aStep, child, aContext, resNodes);
(walker.getNodeType() == txXPathNodeType::TEXT_NODE ||
walker.getNodeType() == txXPathNodeType::CDATA_SECTION_NODE) &&
txXPathNodeUtils::isWhitespace(walker.getCurrentPosition()))) {
rv = evalDescendants(aStep, walker.getCurrentPosition(), aContext,
resNodes);
NS_ENSURE_SUCCESS(rv, rv);
}
child = child->getNextSibling();
}
} while (walker.moveToNextSibling());
return NS_OK;
} //-- evalDescendants

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

@ -67,10 +67,8 @@ PredicateList::evaluatePredicates(txNodeSet* nodes,
txIMatchContext* aContext)
{
NS_ASSERTION(nodes, "called evaluatePredicates with NULL NodeSet");
nsRefPtr<txNodeSet> newNodes;
nsresult rv = aContext->recycler()->getNodeSet(getter_AddRefs(newNodes));
NS_ENSURE_SUCCESS(rv, rv);
nsresult rv = NS_OK;
txListIterator iter(&predicates);
while (iter.hasNext() && !nodes->isEmpty()) {
Expr* expr = (Expr*)iter.next();
@ -80,31 +78,28 @@ PredicateList::evaluatePredicates(txNodeSet* nodes,
* or, if the result is a number, add the node with the right
* position
*/
newNodes->clear();
PRInt32 index = 0;
while (predContext.hasNext()) {
predContext.next();
nsRefPtr<txAExprResult> exprResult;
rv = expr->evaluate(&predContext, getter_AddRefs(exprResult));
NS_ENSURE_SUCCESS(rv, rv);
switch(exprResult->getResultType()) {
case txAExprResult::NUMBER:
// handle default, [position() == numberValue()]
if ((double)predContext.position() ==
exprResult->numberValue())
newNodes->append(predContext.getContextNode());
break;
default:
if (exprResult->booleanValue())
newNodes->append(predContext.getContextNode());
break;
// handle default, [position() == numberValue()]
if (exprResult->getResultType() == txAExprResult::NUMBER) {
if ((double)predContext.position() == exprResult->numberValue()) {
nodes->mark(index);
}
}
else if (exprResult->booleanValue()) {
nodes->mark(index);
}
++index;
}
// Move new NodeSet to the current one
nodes->clear();
nodes->append(newNodes);
// sweep the non-marked nodes
nodes->sweep();
}
return NS_OK;
}

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

@ -29,7 +29,6 @@
#include "Expr.h"
#include "txNodeSet.h"
#include "XMLDOMUtils.h"
#include "txIXPathContext.h"
/**
@ -58,7 +57,8 @@ RelationalExpr::compareResults(txIEvalContext* aContext, txAExprResult* aLeft,
PRInt32 i;
for (i = 0; i < nodeSet->size(); ++i) {
strResult->mValue.Truncate();
XMLDOMUtils::getNodeValue(nodeSet->get(i), strResult->mValue);
txXPathNodeUtils::appendNodeValue(nodeSet->get(i),
strResult->mValue);
if (compareResults(aContext, strResult, aRight)) {
return PR_TRUE;
}
@ -82,7 +82,8 @@ RelationalExpr::compareResults(txIEvalContext* aContext, txAExprResult* aLeft,
PRInt32 i;
for (i = 0; i < nodeSet->size(); ++i) {
strResult->mValue.Truncate();
XMLDOMUtils::getNodeValue(nodeSet->get(i), strResult->mValue);
txXPathNodeUtils::appendNodeValue(nodeSet->get(i),
strResult->mValue);
if (compareResults(aContext, aLeft, strResult)) {
return PR_TRUE;
}
@ -153,20 +154,27 @@ RelationalExpr::compareResults(txIEvalContext* aContext, txAExprResult* aLeft,
switch (mOp) {
case LESS_THAN:
{
return leftDbl < rightDbl;
}
case LESS_OR_EQUAL:
{
return leftDbl <= rightDbl;
case GREATER_THAN :
}
case GREATER_THAN:
{
return leftDbl > rightDbl;
}
case GREATER_OR_EQUAL:
{
return leftDbl >= rightDbl;
}
default:
{
NS_NOTREACHED("We should have caught all cases");
}
}
NS_NOTREACHED("We should have caught all cases");
return PR_FALSE;
}

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

@ -203,7 +203,7 @@ txResultRecycler::getNodeSet(txNodeSet* aNodeSet, txNodeSet** aResult)
else {
*aResult = NS_STATIC_CAST(txNodeSet*, mNodeSetResults.pop());
(*aResult)->clear();
(*aResult)->append(aNodeSet);
(*aResult)->append(*aNodeSet);
(*aResult)->mRecycler = this;
}
NS_ADDREF(*aResult);
@ -212,7 +212,7 @@ txResultRecycler::getNodeSet(txNodeSet* aNodeSet, txNodeSet** aResult)
}
nsresult
txResultRecycler::getNodeSet(Node* aNode, txAExprResult** aResult)
txResultRecycler::getNodeSet(const txXPathNode& aNode, txAExprResult** aResult)
{
if (mNodeSetResults.isEmpty()) {
*aResult = new txNodeSet(aNode, this);
@ -231,7 +231,7 @@ txResultRecycler::getNodeSet(Node* aNode, txAExprResult** aResult)
}
nsresult
txResultRecycler::getNodeSet(Node* aNode, txNodeSet** aResult)
txResultRecycler::getNodeSet(const txXPathNode& aNode, txNodeSet** aResult)
{
if (mNodeSetResults.isEmpty()) {
*aResult = new txNodeSet(aNode, this);

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

@ -45,7 +45,7 @@
class txAExprResult;
class StringResult;
class txNodeSet;
class Node;
class txXPathNode;
class NumberResult;
class BooleanResult;
@ -82,8 +82,8 @@ public:
nsresult getStringResult(const nsAString& aValue, txAExprResult** aResult);
nsresult getNodeSet(txNodeSet** aResult);
nsresult getNodeSet(txNodeSet* aNodeSet, txNodeSet** aResult);
nsresult getNodeSet(Node* aNode, txAExprResult** aResult);
nsresult getNodeSet(Node* aNode, txNodeSet** aResult);
nsresult getNodeSet(const txXPathNode& aNode, txAExprResult** aResult);
nsresult getNodeSet(const txXPathNode& aNode, txNodeSet** aResult);
nsresult getNumberResult(double aValue, txAExprResult** aResult);
/**

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

@ -45,12 +45,21 @@ RootExpr::RootExpr(MBool aSerialize) {
nsresult
RootExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
{
Node* context = aContext->getContextNode();
if (context->getNodeType() != Node::DOCUMENT_NODE) {
context = context->getOwnerDocument();
const txXPathNode& context = aContext->getContextNode();
nsAutoPtr<txXPathNode> document(txXPathNodeUtils::getDocument(context));
if (!document) {
nsRefPtr<txNodeSet> nodes;
aContext->recycler()->getNodeSet(getter_AddRefs(nodes));
if (!nodes) {
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF(*aResult = nodes);
return NS_OK;
}
return aContext->recycler()->getNodeSet(context, aResult);
return aContext->recycler()->getNodeSet(*document, aResult);
} //-- evaluate
/**

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

@ -44,11 +44,11 @@
class txSingleNodeContext : public txIEvalContext
{
public:
txSingleNodeContext(Node* aContextNode, txIMatchContext* aContext)
txSingleNodeContext(const txXPathNode& aContextNode,
txIMatchContext* aContext)
: mNode(aContextNode),
mInner(aContext)
{
NS_ASSERTION(aContextNode, "context node must be given");
NS_ASSERTION(aContext, "txIMatchContext must be given");
}
~txSingleNodeContext()
@ -61,7 +61,7 @@ public:
return mInner->getVariable(aNamespace, aLName, aResult);
}
MBool isStripSpaceAllowed(Node* aNode)
MBool isStripSpaceAllowed(const txXPathNode& aNode)
{
NS_ASSERTION(mInner, "mInner is null!!!");
return mInner->isStripSpaceAllowed(aNode);
@ -91,7 +91,7 @@ public:
#endif
}
Node* getContextNode()
const txXPathNode& getContextNode()
{
return mNode;
}
@ -107,7 +107,7 @@ public:
}
private:
Node* mNode;
const txXPathNode& mNode;
txIMatchContext* mInner;
};

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

@ -33,8 +33,8 @@
#include "FunctionLib.h"
#include "txAtoms.h"
#include "txIXPathContext.h"
#include "XMLDOMUtils.h"
#include "XMLUtils.h"
#include "txXPathTreeWalker.h"
#include <math.h>
#include "nsReadableUtils.h"
@ -105,8 +105,8 @@ StringFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
if (iter.hasNext())
evaluateToString((Expr*)iter.next(), aContext, resultStr);
else
XMLDOMUtils::getNodeValue(aContext->getContextNode(),
resultStr);
txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
resultStr);
nsRefPtr<StringResult> strRes;
rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
@ -164,8 +164,8 @@ StringFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
if (iter.hasNext())
evaluateToString((Expr*)iter.next(), aContext, resultStr);
else
XMLDOMUtils::getNodeValue(aContext->getContextNode(),
resultStr);
txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
resultStr);
rv = aContext->recycler()->getNumberResult(resultStr.Length(),
aResult);
NS_ENSURE_SUCCESS(rv, rv);
@ -280,7 +280,12 @@ StringFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
nsAutoString src;
evaluateToString((Expr*)iter.next(), aContext, src);
if (src.IsEmpty()) {
aContext->recycler()->getEmptyStringResult(aResult);
return NS_OK;
}
nsRefPtr<StringResult> strRes;
rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
NS_ENSURE_SUCCESS(rv, rv);
@ -318,8 +323,8 @@ StringFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
if (iter.hasNext())
evaluateToString((Expr*)iter.next(), aContext, strRes->mValue);
else
XMLDOMUtils::getNodeValue(aContext->getContextNode(),
strRes->mValue);
txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
strRes->mValue);
*aResult = strRes;
NS_ADDREF(*aResult);

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

@ -24,8 +24,8 @@
*/
#include "Expr.h"
#include "txNodeSet.h"
#include "txIXPathContext.h"
#include "txNodeSet.h"
//-------------/
//- UnionExpr -/
@ -93,8 +93,16 @@ UnionExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
//XXX ErrorReport: report nonnodeset error
return NS_ERROR_XSLT_NODESET_EXPECTED;
}
rv = nodes->add(NS_STATIC_CAST(txNodeSet*, NS_STATIC_CAST(txAExprResult*,
exprResult)));
nsRefPtr<txNodeSet> resultSet, ownedSet;
resultSet = NS_STATIC_CAST(txNodeSet*,
NS_STATIC_CAST(txAExprResult*, exprResult));
exprResult = nsnull;
rv = aContext->recycler()->
getNonSharedNodeSet(resultSet, getter_AddRefs(ownedSet));
NS_ENSURE_SUCCESS(rv, rv);
rv = nodes->addAndTransfer(ownedSet);
NS_ENSURE_SUCCESS(rv, rv);
}

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

@ -38,9 +38,9 @@
#include "txAtoms.h"
#include "txIXPathContext.h"
#include "XMLDOMUtils.h"
#include "XSLTFunctions.h"
#include "txExecutionState.h"
#include "txURIUtils.h"
/*
* Creates a new DocumentFunctionCall.
@ -50,6 +50,43 @@ DocumentFunctionCall::DocumentFunctionCall(const nsAString& aBaseURI)
{
}
static void
retrieveNode(txExecutionState* aExecutionState, const nsAString& aUri,
const nsAString& aBaseUri, txNodeSet* aNodeSet)
{
nsAutoString absUrl;
URIUtils::resolveHref(aUri, aBaseUri, absUrl);
PRInt32 hash = absUrl.RFindChar(PRUnichar('#'));
PRUint32 urlEnd, fragStart, fragEnd;
if (hash == kNotFound) {
urlEnd = absUrl.Length();
fragStart = 0;
fragEnd = 0;
}
else {
urlEnd = hash;
fragStart = hash + 1;
fragEnd = absUrl.Length();
}
nsDependentSubstring docUrl(absUrl, 0, urlEnd);
nsDependentSubstring frag(absUrl, fragStart, fragEnd);
const txXPathNode* loadNode = aExecutionState->retrieveDocument(docUrl);
if (loadNode) {
if (frag.IsEmpty()) {
aNodeSet->add(*loadNode);
}
else {
txXPathTreeWalker walker(*loadNode);
if (walker.moveToElementById(frag)) {
aNodeSet->add(walker.getCurrentPosition());
}
}
}
}
/*
* Evaluates this Expr based on the given context node and processor state
* NOTE: the implementation is incomplete since it does not make use of the
@ -97,7 +134,7 @@ DocumentFunctionCall::evaluate(txIEvalContext* aContext,
baseURISet = MB_TRUE;
if (!nodeSet2->isEmpty()) {
nodeSet2->get(0)->getBaseURI(baseURI);
txXPathNodeUtils::getBaseURI(nodeSet2->get(0), baseURI);
}
}
@ -108,18 +145,15 @@ DocumentFunctionCall::evaluate(txIEvalContext* aContext,
exprResult1));
PRInt32 i;
for (i = 0; i < nodeSet1->size(); ++i) {
Node* node = nodeSet1->get(i);
const txXPathNode& node = nodeSet1->get(i);
nsAutoString uriStr;
XMLDOMUtils::getNodeValue(node, uriStr);
txXPathNodeUtils::appendNodeValue(node, uriStr);
if (!baseURISet) {
// if the second argument wasn't specified, use
// the baseUri of node itself
node->getBaseURI(baseURI);
}
Node* loadNode = es->retrieveDocument(uriStr, baseURI);
if (loadNode) {
nodeSet->add(loadNode);
txXPathNodeUtils::getBaseURI(node, baseURI);
}
retrieveNode(es, uriStr, baseURI, nodeSet);
}
NS_ADDREF(*aResult = nodeSet);
@ -130,11 +164,8 @@ DocumentFunctionCall::evaluate(txIEvalContext* aContext,
// The first argument is not a NodeSet
nsAutoString uriStr;
exprResult1->stringValue(uriStr);
nsAString* base = baseURISet ? &baseURI : &mBaseURI;
Node* loadNode = es->retrieveDocument(uriStr, *base);
if (loadNode) {
nodeSet->add(loadNode);
}
const nsAString* base = baseURISet ? &baseURI : &mBaseURI;
retrieveNode(es, uriStr, *base, nodeSet);
NS_ADDREF(*aResult = nodeSet);

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

@ -53,53 +53,41 @@
const PRInt32 txExecutionState::kMaxRecursionDepth = 20000;
DHASH_WRAPPER(txLoadedDocumentsBase, txLoadedDocumentEntry, nsAString&)
nsresult txLoadedDocumentsHash::init(Document* aSourceDocument)
nsresult txLoadedDocumentsHash::init(txXPathNode* aSourceDocument)
{
nsresult rv = Init(8);
NS_ENSURE_SUCCESS(rv, rv);
mSourceDocument = aSourceDocument;
Add(mSourceDocument);
nsAutoString baseURI;
txXPathNodeUtils::getBaseURI(*mSourceDocument, baseURI);
txLoadedDocumentEntry* entry = PutEntry(baseURI);
if (!entry) {
return NS_ERROR_FAILURE;
}
entry->mDocument = mSourceDocument;
return NS_OK;
}
txLoadedDocumentsHash::~txLoadedDocumentsHash()
{
if (!mHashTable.ops) {
if (!IsInitialized()) {
return;
}
nsAutoString baseURI;
mSourceDocument->getBaseURI(baseURI);
txXPathNodeUtils::getBaseURI(*mSourceDocument, baseURI);
txLoadedDocumentEntry* entry = GetEntry(baseURI);
if (entry) {
entry->mDocument = nsnull;
delete entry->mDocument.forget();
}
}
void txLoadedDocumentsHash::Add(Document* aDocument)
{
nsAutoString baseURI;
aDocument->getBaseURI(baseURI);
txLoadedDocumentEntry* entry = AddEntry(baseURI);
if (entry) {
entry->mDocument = aDocument;
}
}
Document* txLoadedDocumentsHash::Get(const nsAString& aURI)
{
txLoadedDocumentEntry* entry = GetEntry(aURI);
if (entry) {
return entry->mDocument;
}
return nsnull;
}
txExecutionState::txExecutionState(txStylesheet* aStylesheet)
: mStylesheet(aStylesheet),
mNextInstruction(nsnull),
@ -110,7 +98,7 @@ txExecutionState::txExecutionState(txStylesheet* aStylesheet)
mTemplateRuleCount(0),
mEvalContext(nsnull),
mInitialEvalContext(nsnull),
mRTFDocument(nsnull),
// mRTFDocument(nsnull),
mGlobalParams(nsnull),
mKeyHash(aStylesheet->getKeyMap())
{
@ -121,7 +109,7 @@ txExecutionState::~txExecutionState()
delete mResultHandler;
delete mLocalVariables;
delete mEvalContext;
delete mRTFDocument;
// delete mRTFDocument;
PRInt32 i;
for (i = 0; i < mTemplateRuleCount; ++i) {
@ -154,7 +142,7 @@ txExecutionState::~txExecutionState()
}
nsresult
txExecutionState::init(Node* aNode,
txExecutionState::init(const txXPathNode& aNode,
txExpandedNameMap* aGlobalParams)
{
nsresult rv = NS_OK;
@ -178,16 +166,15 @@ txExecutionState::init(Node* aNode,
mOutputHandler->startDocument();
// Set up loaded-documents-hash
Document* sourceDoc;
if (aNode->getNodeType() == Node::DOCUMENT_NODE) {
sourceDoc = (Document*)aNode;
}
else {
sourceDoc = aNode->getOwnerDocument();
}
rv = mLoadedDocuments.init(sourceDoc);
nsAutoPtr<txXPathNode> document(txXPathNodeUtils::getOwnerDocument(aNode));
NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
rv = mLoadedDocuments.init(document);
NS_ENSURE_SUCCESS(rv, rv);
// loaded-documents-hash owns this now
document.forget();
// Init members
rv = mKeyHash.init();
NS_ENSURE_SUCCESS(rv, rv);
@ -338,7 +325,7 @@ txExecutionState::getVariable(PRInt32 aNamespace, nsIAtom* aLName,
}
PRBool
txExecutionState::isStripSpaceAllowed(Node* aNode)
txExecutionState::isStripSpaceAllowed(const txXPathNode& aNode)
{
return mStylesheet->isStripSpaceAllowed(aNode, this);
}
@ -474,70 +461,47 @@ txExecutionState::getEvalContext()
return mEvalContext;
}
Node*
txExecutionState::retrieveDocument(const nsAString& uri,
const nsAString& baseUri)
const txXPathNode*
txExecutionState::retrieveDocument(const nsAString& aUri)
{
nsAutoString absUrl;
URIUtils::resolveHref(uri, baseUri, absUrl);
PRInt32 hash = absUrl.RFindChar(PRUnichar('#'));
PRUint32 urlEnd, fragStart, fragEnd;
if (hash == kNotFound) {
urlEnd = absUrl.Length();
fragStart = 0;
fragEnd = 0;
}
else {
urlEnd = hash;
fragStart = hash + 1;
fragEnd = absUrl.Length();
}
nsDependentSubstring docUrl(absUrl, 0, urlEnd);
nsDependentSubstring frag(absUrl, fragStart, fragEnd);
NS_ASSERTION(aUri.FindChar(PRUnichar('#')) == kNotFound,
"Remove the fragment.");
PR_LOG(txLog::xslt, PR_LOG_DEBUG,
("Retrieve Document %s, uri %s, baseUri %s, fragment %s\n",
NS_LossyConvertUCS2toASCII(docUrl).get(),
NS_LossyConvertUCS2toASCII(uri).get(),
NS_LossyConvertUCS2toASCII(baseUri).get(),
NS_LossyConvertUCS2toASCII(frag).get()));
("Retrieve Document %s", NS_LossyConvertUCS2toASCII(aUri).get()));
// try to get already loaded document
Document* xmlDoc = mLoadedDocuments.Get(docUrl);
txLoadedDocumentEntry *entry = mLoadedDocuments.PutEntry(aUri);
if (!entry) {
return nsnull;
}
if (!xmlDoc) {
if (!entry->mDocument) {
// open URI
nsAutoString errMsg, refUri;
// XXX we should get the referrer from the actual node
// triggering the load, but this will do for the time being
mLoadedDocuments.mSourceDocument->getBaseURI(refUri);
txXPathNodeUtils::getBaseURI(*mLoadedDocuments.mSourceDocument, refUri);
nsresult rv;
rv = txParseDocumentFromURI(docUrl, refUri,
mLoadedDocuments.mSourceDocument, errMsg,
&xmlDoc);
rv = txParseDocumentFromURI(aUri, refUri,
*mLoadedDocuments.mSourceDocument, errMsg,
getter_Transfers(entry->mDocument));
if (NS_FAILED(rv) || !xmlDoc) {
if (NS_FAILED(rv) || !entry->mDocument) {
mLoadedDocuments.RawRemoveEntry(entry);
receiveError(NS_LITERAL_STRING("Couldn't load document '") +
docUrl + NS_LITERAL_STRING("': ") + errMsg, rv);
aUri + NS_LITERAL_STRING("': ") + errMsg, rv);
return nsnull;
}
// add to list of documents
mLoadedDocuments.Add(xmlDoc);
}
// return element with supplied id if supplied
if (!frag.IsEmpty()) {
return xmlDoc->getElementById(frag);
}
return xmlDoc;
return entry->mDocument;
}
nsresult
txExecutionState::getKeyNodes(const txExpandedName& aKeyName,
Document* aDocument,
const txXPathNode& aDocument,
const nsAString& aKeyValue,
PRBool aIndexIfNotFound,
txNodeSet** aResult)

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

@ -47,7 +47,8 @@
#include "nsVoidArray.h"
#include "txIXPathContext.h"
#include "txVariableMap.h"
#include "nsDoubleHashtable.h"
#include "nsTHashtable.h"
#include "nsHashKeys.h"
#include "txKey.h"
#include "txStylesheet.h"
@ -55,32 +56,36 @@ class txInstruction;
class txIOutputHandlerFactory;
class txExpandedNameMap;
class txLoadedDocumentEntry : public PLDHashStringEntry
class txLoadedDocumentEntry : public nsStringHashKey
{
public:
txLoadedDocumentEntry(const void* aKey) : PLDHashStringEntry(aKey)
txLoadedDocumentEntry(KeyTypePointer aStr) : nsStringHashKey(aStr)
{
}
txLoadedDocumentEntry(const txLoadedDocumentEntry& aToCopy)
: nsStringHashKey(aToCopy)
{
NS_ERROR("We're horked.");
}
~txLoadedDocumentEntry()
{
delete mDocument;
if (mDocument) {
txXPathNodeUtils::release(mDocument);
}
}
Document* mDocument;
nsAutoPtr<txXPathNode> mDocument;
};
DECL_DHASH_WRAPPER(txLoadedDocumentsBase, txLoadedDocumentEntry, nsAString&)
class txLoadedDocumentsHash : public txLoadedDocumentsBase
class txLoadedDocumentsHash : public nsTHashtable<txLoadedDocumentEntry>
{
public:
~txLoadedDocumentsHash();
nsresult init(Document* aSourceDocument);
void Add(Document* aDocument);
Document* Get(const nsAString& aURI);
nsresult init(txXPathNode* aSourceDocument);
private:
friend class txExecutionState;
Document* mSourceDocument;
txXPathNode* mSourceDocument;
};
@ -89,7 +94,7 @@ class txExecutionState : public txIMatchContext
public:
txExecutionState(txStylesheet* aStylesheet);
~txExecutionState();
nsresult init(Node* aNode, txExpandedNameMap* aGlobalParams);
nsresult init(const txXPathNode& aNode, txExpandedNameMap* aGlobalParams);
nsresult end();
TX_DECL_MATCH_CONTEXT;
@ -123,8 +128,9 @@ public:
// state-getting functions
txIEvalContext* getEvalContext();
txExpandedNameMap* getParamMap();
Node* retrieveDocument(const nsAString& uri, const nsAString& baseUri);
nsresult getKeyNodes(const txExpandedName& aKeyName, Document* aDocument,
const txXPathNode* retrieveDocument(const nsAString& aUri);
nsresult getKeyNodes(const txExpandedName& aKeyName,
const txXPathNode& aDocument,
const nsAString& aKeyValue, PRBool aIndexIfNotFound,
txNodeSet** aResult);
TemplateRule* getCurrentTemplateRule();
@ -168,7 +174,7 @@ private:
txIEvalContext* mEvalContext;
txIEvalContext* mInitialEvalContext;
Document* mRTFDocument;
//Document* mRTFDocument;
txExpandedNameMap* mGlobalParams;
txLoadedDocumentsHash mLoadedDocuments;

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

@ -22,22 +22,16 @@
*
*/
#include "ExprResult.h"
#include "txAtoms.h"
#include "txIXPathContext.h"
#include "XSLTFunctions.h"
#include "prprf.h"
#include "txNodeSet.h"
#include "XSLTFunctions.h"
/*
Implementation of XSLT 1.0 extension function: generate-id
*/
#ifndef HAVE_64BIT_OS
const char GenerateIdFunctionCall::printfFmt[] = "id0x%08p";
#else
const char GenerateIdFunctionCall::printfFmt[] = "id0x%016p";
#endif
/**
* Creates a new generate-id function call
**/
@ -61,43 +55,41 @@ GenerateIdFunctionCall::evaluate(txIEvalContext* aContext,
if (!requireParams(0, 1, aContext))
return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
Node* node = 0;
// get node to generate id for
if (params.getLength() == 1) {
txListIterator iter(&params);
Expr* param = (Expr*)iter.next();
nsRefPtr<txAExprResult> exprResult;
nsresult rv = param->evaluate(aContext, getter_AddRefs(exprResult));
nsresult rv = NS_OK;
if (params.getLength() != 1) {
StringResult* strRes;
rv = aContext->recycler()->getStringResult(&strRes);
NS_ENSURE_SUCCESS(rv, rv);
if (exprResult->getResultType() != txAExprResult::NODESET) {
NS_NAMED_LITERAL_STRING(err, "Invalid argument passed to generate-id(), expecting NodeSet");
aContext->receiveError(err, NS_ERROR_XSLT_NODESET_EXPECTED);
return NS_ERROR_XSLT_NODESET_EXPECTED;
}
txXPathNodeUtils::getXSLTId(aContext->getContextNode(),
strRes->mValue);
txNodeSet* nodes = NS_STATIC_CAST(txNodeSet*,
NS_STATIC_CAST(txAExprResult*,
exprResult));
if (nodes->isEmpty()) {
aContext->recycler()->getEmptyStringResult(aResult);
return NS_OK;
}
node = nodes->get(0);
}
else {
node = aContext->getContextNode();
*aResult = strRes;
return NS_OK;
}
// generate id for selected node
char buf[22];
PR_snprintf(buf, 21, printfFmt, node);
return aContext->recycler()->getStringResult(NS_ConvertASCIItoUCS2(buf),
aResult);
txListIterator iter(&params);
nsRefPtr<txNodeSet> nodes;
rv = evaluateToNodeSet(NS_STATIC_CAST(Expr*, iter.next()), aContext,
getter_AddRefs(nodes));
NS_ENSURE_SUCCESS(rv, rv);
if (nodes->isEmpty()) {
aContext->recycler()->getEmptyStringResult(aResult);
return NS_OK;
}
StringResult* strRes;
rv = aContext->recycler()->getStringResult(&strRes);
NS_ENSURE_SUCCESS(rv, rv);
txXPathNodeUtils::getXSLTId(nodes->get(0), strRes->mValue);
*aResult = strRes;
return NS_OK;
}
nsresult GenerateIdFunctionCall::getNameAtom(nsIAtom** aAtom)

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

@ -278,84 +278,82 @@ txComment::execute(txExecutionState& aEs)
}
nsresult
txCopyBase::copyNode(Node* aNode, txExecutionState& aEs)
txCopyBase::copyNode(const txXPathNode& aNode, txExecutionState& aEs)
{
NS_ASSERTION(aNode, "missing node to copy");
switch (aNode->getNodeType()) {
case Node::ATTRIBUTE_NODE:
switch (txXPathNodeUtils::getNodeType(aNode)) {
case txXPathNodeType::ATTRIBUTE_NODE:
{
nsAutoString nodeName, nodeValue;
aNode->getNodeName(nodeName);
aNode->getNodeValue(nodeValue);
txXPathNodeUtils::getNodeName(aNode, nodeName);
txXPathNodeUtils::appendNodeValue(aNode, nodeValue);
aEs.mResultHandler->attribute(nodeName,
aNode->getNamespaceID(),
txXPathNodeUtils::getNamespaceID(aNode),
nodeValue);
break;
}
case Node::COMMENT_NODE:
case txXPathNodeType::COMMENT_NODE:
{
nsAutoString nodeValue;
aNode->getNodeValue(nodeValue);
txXPathNodeUtils::appendNodeValue(aNode, nodeValue);
aEs.mResultHandler->comment(nodeValue);
break;
}
case Node::DOCUMENT_NODE:
case Node::DOCUMENT_FRAGMENT_NODE:
case txXPathNodeType::DOCUMENT_NODE:
case txXPathNodeType::DOCUMENT_FRAGMENT_NODE:
{
// Copy children
Node* child = aNode->getFirstChild();
while (child) {
copyNode(child, aEs);
child = child->getNextSibling();
txXPathTreeWalker walker(aNode);
PRBool hasChild = walker.moveToFirstChild();
while (hasChild) {
copyNode(walker.getCurrentPosition(), aEs);
hasChild = walker.moveToNextSibling();
}
break;
}
case Node::ELEMENT_NODE:
case txXPathNodeType::ELEMENT_NODE:
{
Element* element = NS_STATIC_CAST(Element*, aNode);
nsAutoString name;
element->getNodeName(name);
PRInt32 nsID = element->getNamespaceID();
txXPathNodeUtils::getNodeName(aNode, name);
PRInt32 nsID = txXPathNodeUtils::getNamespaceID(aNode);
aEs.mResultHandler->startElement(name, nsID);
// Copy attributes
NamedNodeMap* attList = element->getAttributes();
if (attList) {
PRUint32 i = 0;
for (i = 0; i < attList->getLength(); i++) {
Attr* attr = NS_STATIC_CAST(Attr*, attList->item(i));
txXPathTreeWalker walker(aNode);
if (walker.moveToFirstAttribute()) {
do {
nsAutoString nodeName, nodeValue;
attr->getNodeName(nodeName);
attr->getNodeValue(nodeValue);
walker.getNodeName(nodeName);
walker.appendNodeValue(nodeValue);
aEs.mResultHandler->attribute(nodeName,
attr->getNamespaceID(),
walker.getNamespaceID(),
nodeValue);
}
} while (walker.moveToNextAttribute());
walker.moveToParent();
}
// Copy children
Node* child = element->getFirstChild();
while (child) {
copyNode(child, aEs);
child = child->getNextSibling();
PRBool hasChild = walker.moveToFirstChild();
while (hasChild) {
copyNode(walker.getCurrentPosition(), aEs);
hasChild = walker.moveToNextSibling();
}
aEs.mResultHandler->endElement(name, nsID);
break;
}
case Node::PROCESSING_INSTRUCTION_NODE:
case txXPathNodeType::PROCESSING_INSTRUCTION_NODE:
{
nsAutoString target, data;
aNode->getNodeName(target);
aNode->getNodeValue(data);
txXPathNodeUtils::getNodeName(aNode, target);
txXPathNodeUtils::appendNodeValue(aNode, data);
aEs.mResultHandler->processingInstruction(target, data);
break;
}
case Node::TEXT_NODE:
case Node::CDATA_SECTION_NODE:
case txXPathNodeType::TEXT_NODE:
case txXPathNodeType::CDATA_SECTION_NODE:
{
nsAutoString nodeValue;
aNode->getNodeValue(nodeValue);
txXPathNodeUtils::appendNodeValue(aNode, nodeValue);
aEs.mResultHandler->characters(nodeValue, PR_FALSE);
break;
}
@ -373,10 +371,10 @@ nsresult
txCopy::execute(txExecutionState& aEs)
{
nsresult rv = NS_OK;
Node* node = aEs.getEvalContext()->getContextNode();
const txXPathNode& node = aEs.getEvalContext()->getContextNode();
switch (node->getNodeType()) {
case Node::DOCUMENT_NODE:
switch (txXPathNodeUtils::getNodeType(node)) {
case txXPathNodeType::DOCUMENT_NODE:
{
// "close" current element to ensure that no attributes are added
aEs.mResultHandler->characters(NS_LITERAL_STRING(""), PR_FALSE);
@ -389,11 +387,11 @@ txCopy::execute(txExecutionState& aEs)
break;
}
case Node::ELEMENT_NODE:
case txXPathNodeType::ELEMENT_NODE:
{
nsAutoString nodeName;
node->getNodeName(nodeName);
PRInt32 nsID = node->getNamespaceID();
txXPathNodeUtils::getNodeName(node, nodeName);
PRInt32 nsID = txXPathNodeUtils::getNamespaceID(node);
aEs.mResultHandler->startElement(nodeName, nsID);
// XXX copy namespace nodes once we have them

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

@ -154,7 +154,7 @@ public:
class txCopyBase : public txInstruction
{
protected:
nsresult copyNode(Node* aNode, txExecutionState& aEs);
nsresult copyNode(const txXPathNode& aNode, txExecutionState& aEs);
};
class txCopy : public txCopyBase

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

@ -53,17 +53,17 @@ class txKeyValueHashKey
{
public:
txKeyValueHashKey(const txExpandedName& aKeyName,
Document* aDocument,
PRInt32 aDocumentIdentifier,
const nsAString& aKeyValue)
: mKeyName(aKeyName),
mKeyValue(aKeyValue),
mDocument(aDocument)
mDocumentIdentifier(aDocumentIdentifier)
{
}
txExpandedName mKeyName;
nsString mKeyValue;
Document* mDocument;
PRInt32 mDocumentIdentifier;
};
struct txKeyValueHashEntry : public PLDHashEntryHdr
@ -89,14 +89,14 @@ class txIndexedKeyHashKey
{
public:
txIndexedKeyHashKey(txExpandedName aKeyName,
Document* aDocument)
PRInt32 aDocumentIdentifier)
: mKeyName(aKeyName),
mDocument(aDocument)
mDocumentIdentifier(aDocumentIdentifier)
{
}
txExpandedName mKeyName;
Document* mDocument;
PRInt32 mDocumentIdentifier;
};
struct txIndexedKeyHashEntry : public PLDHashEntryHdr
@ -145,7 +145,7 @@ public:
* @param aKeyValueHash Hash to add values to
* @param aEs txExecutionState to use for XPath evaluation
*/
nsresult indexDocument(Document* aDocument,
nsresult indexDocument(const txXPathNode& aDocument,
txKeyValueHash& aKeyValueHash,
txExecutionState& aEs);
@ -158,7 +158,7 @@ private:
* @param aKeyValueHash Hash to add values to
* @param aEs txExecutionState to use for XPath evaluation
*/
nsresult indexTree(Node* aNode, txKeyValueHashKey& aKey,
nsresult indexTree(const txXPathNode& aNode, txKeyValueHashKey& aKey,
txKeyValueHash& aKeyValueHash, txExecutionState& aEs);
/**
@ -169,7 +169,7 @@ private:
* @param aKeyValueHash Hash to add values to
* @param aEs txExecutionState to use for XPath evaluation
*/
nsresult testNode(Node* aNode, txKeyValueHashKey& aKey,
nsresult testNode(const txXPathNode& aNode, txKeyValueHashKey& aKey,
txKeyValueHash& aKeyValueHash, txExecutionState& aEs);
/**
@ -203,7 +203,7 @@ public:
nsresult init();
nsresult getKeyNodes(const txExpandedName& aKeyName,
Document* aDocument,
const txXPathNode& aDocument,
const nsAString& aKeyValue,
PRBool aIndexIfNotFound,
txExecutionState& aEs,

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

@ -21,7 +21,6 @@
#include "txExecutionState.h"
#include "txAtoms.h"
#include "txSingleNodeContext.h"
#include "XMLDOMUtils.h"
#include "XSLTFunctions.h"
#include "nsReadableUtils.h"
#include "txKey.h"
@ -70,12 +69,8 @@ txKeyFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
rv = ((Expr*)iter.next())->evaluate(aContext, getter_AddRefs(exprResult));
NS_ENSURE_SUCCESS(rv, rv);
Document* contextDoc;
Node* contextNode = aContext->getContextNode();
if (contextNode->getNodeType() == Node::DOCUMENT_NODE)
contextDoc = (Document*)contextNode;
else
contextDoc = contextNode->getOwnerDocument();
nsAutoPtr<txXPathNode> contextDoc(txXPathNodeUtils::getOwnerDocument(aContext->getContextNode()));
NS_ENSURE_TRUE(contextDoc, NS_ERROR_FAILURE);
nsRefPtr<txNodeSet> res;
txNodeSet* nodeSet;
@ -89,20 +84,20 @@ txKeyFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
PRInt32 i;
for (i = 0; i < nodeSet->size(); ++i) {
nsAutoString val;
XMLDOMUtils::getNodeValue(nodeSet->get(i), val);
txXPathNodeUtils::appendNodeValue(nodeSet->get(i), val);
nsRefPtr<txNodeSet> nodes;
rv = es->getKeyNodes(keyName, contextDoc, val, i == 0,
rv = es->getKeyNodes(keyName, *contextDoc, val, i == 0,
getter_AddRefs(nodes));
NS_ENSURE_SUCCESS(rv, rv);
res->add(nodes);
res->add(*nodes);
}
}
else {
nsAutoString val;
exprResult->stringValue(val);
rv = es->getKeyNodes(keyName, contextDoc, val, PR_TRUE,
rv = es->getKeyNodes(keyName, *contextDoc, val, PR_TRUE,
getter_AddRefs(res));
NS_ENSURE_SUCCESS(rv, rv);
}
@ -140,7 +135,7 @@ txKeyValueHashEntry::MatchEntry(const void* aKey) const
NS_STATIC_CAST(const txKeyValueHashKey*, aKey);
return mKey.mKeyName == key->mKeyName &&
mKey.mDocument == key->mDocument &&
mKey.mDocumentIdentifier == key->mDocumentIdentifier &&
mKey.mKeyValue.Equals(key->mKeyValue);
}
@ -152,7 +147,7 @@ txKeyValueHashEntry::HashKey(const void* aKey)
return key->mKeyName.mNamespaceID ^
NS_PTR_TO_INT32(key->mKeyName.mLocalName.get()) ^
NS_PTR_TO_INT32(key->mDocument) ^
key->mDocumentIdentifier ^
HashString(key->mKeyValue);
}
@ -169,7 +164,7 @@ txIndexedKeyHashEntry::MatchEntry(const void* aKey) const
NS_STATIC_CAST(const txIndexedKeyHashKey*, aKey);
return mKey.mKeyName == key->mKeyName &&
mKey.mDocument == key->mDocument;
mKey.mDocumentIdentifier == key->mDocumentIdentifier;
}
PLDHashNumber
@ -180,7 +175,7 @@ txIndexedKeyHashEntry::HashKey(const void* aKey)
return key->mKeyName.mNamespaceID ^
NS_PTR_TO_INT32(key->mKeyName.mLocalName.get()) ^
NS_PTR_TO_INT32(key->mDocument);
key->mDocumentIdentifier;
}
/*
@ -189,7 +184,7 @@ txIndexedKeyHashEntry::HashKey(const void* aKey)
nsresult
txKeyHash::getKeyNodes(const txExpandedName& aKeyName,
Document* aDocument,
const txXPathNode& aDocument,
const nsAString& aKeyValue,
PRBool aIndexIfNotFound,
txExecutionState& aEs,
@ -199,7 +194,10 @@ txKeyHash::getKeyNodes(const txExpandedName& aKeyName,
NS_ERROR_OUT_OF_MEMORY);
*aResult = nsnull;
txKeyValueHashKey valueKey(aKeyName, aDocument, aKeyValue);
PRInt32 identifier = txXPathNodeUtils::getUniqueIdentifier(aDocument);
txKeyValueHashKey valueKey(aKeyName, identifier, aKeyValue);
txKeyValueHashEntry* valueEntry = mKeyValues.GetEntry(valueKey);
if (valueEntry) {
*aResult = valueEntry->mNodeSet;
@ -221,7 +219,7 @@ txKeyHash::getKeyNodes(const txExpandedName& aKeyName,
return NS_OK;
}
txIndexedKeyHashKey indexKey(aKeyName, aDocument);
txIndexedKeyHashKey indexKey(aKeyName, identifier);
txIndexedKeyHashEntry* indexEntry = mIndexedKeys.AddEntry(indexKey);
NS_ENSURE_TRUE(indexEntry, NS_ERROR_OUT_OF_MEMORY);
@ -230,6 +228,7 @@ txKeyHash::getKeyNodes(const txExpandedName& aKeyName,
// return the empty nodeset.
*aResult = mEmptyNodeSet;
NS_ADDREF(*aResult);
return NS_OK;
}
@ -318,11 +317,13 @@ PRBool txXSLKey::addKey(nsAutoPtr<txPattern> aMatch, nsAutoPtr<Expr> aUse)
* @param aKeyValueHash Hash to add values to
* @param aEs txExecutionState to use for XPath evaluation
*/
nsresult txXSLKey::indexDocument(Document* aDocument,
nsresult txXSLKey::indexDocument(const txXPathNode& aDocument,
txKeyValueHash& aKeyValueHash,
txExecutionState& aEs)
{
txKeyValueHashKey key(mName, aDocument, NS_LITERAL_STRING(""));
txKeyValueHashKey key(mName,
txXPathNodeUtils::getUniqueIdentifier(aDocument),
NS_LITERAL_STRING(""));
return indexTree(aDocument, key, aKeyValueHash, aEs);
}
@ -334,30 +335,34 @@ nsresult txXSLKey::indexDocument(Document* aDocument,
* @param aKeyValueHash Hash to add values to
* @param aEs txExecutionState to use for XPath evaluation
*/
nsresult txXSLKey::indexTree(Node* aNode, txKeyValueHashKey& aKey,
nsresult txXSLKey::indexTree(const txXPathNode& aNode,
txKeyValueHashKey& aKey,
txKeyValueHash& aKeyValueHash,
txExecutionState& aEs)
{
nsresult rv = testNode(aNode, aKey, aKeyValueHash, aEs);
NS_ENSURE_SUCCESS(rv, rv);
// check if the nodes attributes matches
NamedNodeMap* attrs = aNode->getAttributes();
if (attrs) {
for (PRUint32 i=0; i<attrs->getLength(); i++) {
rv = testNode(attrs->item(i), aKey, aKeyValueHash, aEs);
// check if the node's attributes match
txXPathTreeWalker walker(aNode);
if (walker.moveToFirstAttribute()) {
do {
rv = testNode(walker.getCurrentPosition(), aKey, aKeyValueHash,
aEs);
NS_ENSURE_SUCCESS(rv, rv);
}
} while (walker.moveToNextAttribute());
walker.moveToParent();
}
Node* child = aNode->getFirstChild();
while (child) {
rv = indexTree(child, aKey, aKeyValueHash, aEs);
NS_ENSURE_SUCCESS(rv, rv);
child = child->getNextSibling();
// check if the node's descendants match
if (walker.moveToFirstChild()) {
do {
rv = indexTree(walker.getCurrentPosition(), aKey, aKeyValueHash,
aEs);
NS_ENSURE_SUCCESS(rv, rv);
} while (walker.moveToNextSibling());
}
return NS_OK;
}
@ -369,7 +374,7 @@ nsresult txXSLKey::indexTree(Node* aNode, txKeyValueHashKey& aKey,
* @param aKeyValueHash Hash to add values to
* @param aEs txExecutionState to use for XPath evaluation
*/
nsresult txXSLKey::testNode(Node* aNode,
nsresult txXSLKey::testNode(const txXPathNode& aNode,
txKeyValueHashKey& aKey,
txKeyValueHash& aKeyValueHash,
txExecutionState& aEs)
@ -398,7 +403,7 @@ nsresult txXSLKey::testNode(Node* aNode,
PRInt32 i;
for (i = 0; i < res->size(); ++i) {
val.Truncate();
XMLDOMUtils::getNodeValue(res->get(i), val);
txXPathNodeUtils::appendNodeValue(res->get(i), val);
aKey.mKeyValue.Assign(val);
txKeyValueHashEntry* entry = aKeyValueHash.AddEntry(aKey);

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

@ -630,7 +630,7 @@ handleNode(nsIDOMNode* aNode, txStylesheetCompiler* aCompiler)
{
nsCOMPtr<nsIDocument> document = do_QueryInterface(aNode);
PRInt32 counter = 0;
PRUint32 counter = 0;
nsIContent *child;
while ((child = document->GetChildAt(counter++))) {
nsCOMPtr<nsIDOMNode> childNode = do_QueryInterface(child);

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

@ -57,7 +57,6 @@
#include "txExecutionState.h"
#include "txMozillaTextOutput.h"
#include "txMozillaXMLOutput.h"
#include "txSingleNodeContext.h"
#include "txURIUtils.h"
#include "XMLUtils.h"
#include "txUnknownHandler.h"
@ -290,24 +289,27 @@ txMozillaXSLTProcessor::TransformDocument(nsIDOMNode* aSourceDOM,
nsresult rv = TX_CompileStylesheet(aStyleDOM, getter_AddRefs(mStylesheet));
NS_ENSURE_SUCCESS(rv, rv);
// Create wrapper for the source document.
mSource = aSourceDOM;
nsCOMPtr<nsIDOMDocument> sourceDOMDocument;
mSource->GetOwnerDocument(getter_AddRefs(sourceDOMDocument));
if (!sourceDOMDocument) {
sourceDOMDocument = do_QueryInterface(mSource);
nsAutoPtr<txXPathNode> sourceNode(txXPathNativeNode::createXPathNode(aSourceDOM));
if (!sourceNode) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsCOMPtr<nsIDOMDocument> sourceDOMDocument;
aSourceDOM->GetOwnerDocument(getter_AddRefs(sourceDOMDocument));
if (!sourceDOMDocument) {
sourceDOMDocument = do_QueryInterface(aSourceDOM);
}
NS_ENSURE_TRUE(sourceDOMDocument, NS_ERROR_FAILURE);
Document sourceDocument(sourceDOMDocument);
Node* sourceNode = sourceDocument.createWrapper(mSource);
NS_ENSURE_TRUE(sourceNode, NS_ERROR_FAILURE);
txExecutionState es(mStylesheet);
txToDocHandlerFactory handlerFactory(&es, sourceDOMDocument, aOutputDoc,
nsnull);
es.mOutputHandlerFactory = &handlerFactory;
es.init(sourceNode, &mVariables);
es.init(*sourceNode, &mVariables);
// Process root of XML source document
rv = txXSLTProcessor::execute(es);
@ -348,16 +350,16 @@ txMozillaXSLTProcessor::DoTransform()
NS_ENSURE_TRUE(mStylesheet, NS_ERROR_UNEXPECTED);
NS_ASSERTION(mObserver, "no observer");
// Create wrapper for the source document.
nsAutoPtr<txXPathNode> sourceNode(txXPathNativeNode::createXPathNode(mSource));
if (!sourceNode) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsCOMPtr<nsIDOMDocument> sourceDOMDocument;
mSource->GetOwnerDocument(getter_AddRefs(sourceDOMDocument));
if (!sourceDOMDocument) {
sourceDOMDocument = do_QueryInterface(mSource);
}
NS_ENSURE_TRUE(sourceDOMDocument, NS_ERROR_FAILURE);
Document sourceDocument(sourceDOMDocument);
Node* sourceNode = sourceDocument.createWrapper(mSource);
NS_ENSURE_TRUE(sourceNode, NS_ERROR_FAILURE);
txExecutionState es(mStylesheet);
@ -367,7 +369,7 @@ txMozillaXSLTProcessor::DoTransform()
mObserver);
es.mOutputHandlerFactory = &handlerFactory;
es.init(sourceNode, &mVariables);
es.init(*sourceNode, &mVariables);
// Process root of XML source document
nsresult rv = txXSLTProcessor::execute(es);
@ -437,16 +439,16 @@ txMozillaXSLTProcessor::TransformToDocument(nsIDOMNode *aSource,
nsresult rv = ensureStylesheet();
NS_ENSURE_SUCCESS(rv, rv);
// Create wrapper for the source document.
nsAutoPtr<txXPathNode> sourceNode(txXPathNativeNode::createXPathNode(aSource));
if (!sourceNode) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsCOMPtr<nsIDOMDocument> sourceDOMDocument;
aSource->GetOwnerDocument(getter_AddRefs(sourceDOMDocument));
if (!sourceDOMDocument) {
sourceDOMDocument = do_QueryInterface(aSource);
}
NS_ENSURE_TRUE(sourceDOMDocument, NS_ERROR_FAILURE);
Document sourceDocument(sourceDOMDocument);
Node* sourceNode = sourceDocument.createWrapper(aSource);
NS_ENSURE_TRUE(sourceNode, NS_ERROR_FAILURE);
txExecutionState es(mStylesheet);
@ -456,7 +458,7 @@ txMozillaXSLTProcessor::TransformToDocument(nsIDOMNode *aSource,
nsnull);
es.mOutputHandlerFactory = &handlerFactory;
es.init(sourceNode, &mVariables);
es.init(*sourceNode, &mVariables);
// Process root of XML source document
rv = txXSLTProcessor::execute(es);
@ -490,16 +492,10 @@ txMozillaXSLTProcessor::TransformToFragment(nsIDOMNode *aSource,
nsresult rv = ensureStylesheet();
NS_ENSURE_SUCCESS(rv, rv);
// Create wrapper for the source document.
nsCOMPtr<nsIDOMDocument> sourceDOMDocument;
aSource->GetOwnerDocument(getter_AddRefs(sourceDOMDocument));
if (!sourceDOMDocument) {
sourceDOMDocument = do_QueryInterface(aSource);
nsAutoPtr<txXPathNode> sourceNode(txXPathNativeNode::createXPathNode(aSource));
if (!sourceNode) {
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ENSURE_TRUE(sourceDOMDocument, NS_ERROR_FAILURE);
Document sourceDocument(sourceDOMDocument);
Node* sourceNode = sourceDocument.createWrapper(aSource);
NS_ENSURE_TRUE(sourceNode, NS_ERROR_FAILURE);
txExecutionState es(mStylesheet);
@ -510,7 +506,7 @@ txMozillaXSLTProcessor::TransformToFragment(nsIDOMNode *aSource,
txToFragmentHandlerFactory handlerFactory(*aResult);
es.mOutputHandlerFactory = &handlerFactory;
es.init(sourceNode, &mVariables);
es.init(*sourceNode, &mVariables);
// Process root of XML source document
rv = txXSLTProcessor::execute(es);

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

@ -45,7 +45,6 @@
#include "ExprResult.h"
#include "Expr.h"
#include "txStringUtils.h"
#include "txNodeSet.h"
#include "prmem.h"
#include "nsQuickSort.h"

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

@ -43,10 +43,10 @@
#include "baseutils.h"
#include "List.h"
#include "nsIAtom.h"
#include "txXPathNode.h"
class Element;
class Expr;
class Node;
class txExecutionState;
class txNodeSet;
class TxObject;

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

@ -317,11 +317,11 @@ nsresult txPatternParser::createStepPattern(txExprLexer& aLexer,
}
if (isAttr) {
nodeTest = new txNameTest(prefix, lName, nspace,
Node::ATTRIBUTE_NODE);
txXPathNodeType::ATTRIBUTE_NODE);
}
else {
nodeTest = new txNameTest(prefix, lName, nspace,
Node::ELEMENT_NODE);
txXPathNodeType::ELEMENT_NODE);
}
if (!nodeTest) {
return NS_ERROR_OUT_OF_MEMORY;

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

@ -43,7 +43,6 @@
#include "nsCRT.h"
#include "nsReadableUtils.h"
#include "txHTMLOutput.h"
#include "txSingleNodeContext.h"
#include "txTextOutput.h"
#include "txUnknownHandler.h"
#include "txURIUtils.h"
@ -127,13 +126,13 @@ nsresult
txStandaloneXSLTProcessor::transform(nsACString& aXMLPath, ostream& aOut,
ErrorObserver& aErr)
{
Document* xmlDoc = parsePath(aXMLPath, aErr);
txXPathNode* xmlDoc = parsePath(aXMLPath, aErr);
if (!xmlDoc) {
return NS_ERROR_FAILURE;
}
// transform
nsresult rv = transform(xmlDoc, aOut, aErr);
nsresult rv = transform(*xmlDoc, aOut, aErr);
delete xmlDoc;
@ -149,7 +148,7 @@ txStandaloneXSLTProcessor::transform(nsACString& aXMLPath,
nsACString& aXSLPath, ostream& aOut,
ErrorObserver& aErr)
{
Document* xmlDoc = parsePath(aXMLPath, aErr);
txXPathNode* xmlDoc = parsePath(aXMLPath, aErr);
if (!xmlDoc) {
return NS_ERROR_FAILURE;
}
@ -162,7 +161,7 @@ txStandaloneXSLTProcessor::transform(nsACString& aXMLPath,
return rv;
}
// transform
rv = transform(xmlDoc, style, aOut, aErr);
rv = transform(*xmlDoc, style, aOut, aErr);
delete xmlDoc;
@ -175,24 +174,24 @@ txStandaloneXSLTProcessor::transform(nsACString& aXMLPath,
* or an error is returned.
*/
nsresult
txStandaloneXSLTProcessor::transform(Document* aXMLDoc, ostream& aOut,
txStandaloneXSLTProcessor::transform(txXPathNode& aXMLDoc, ostream& aOut,
ErrorObserver& aErr)
{
if (!aXMLDoc) {
return NS_ERROR_INVALID_POINTER;
}
Document* xmlDoc;
nsresult rv = txXPathNativeNode::getDocument(aXMLDoc, &xmlDoc);
NS_ENSURE_SUCCESS(rv, rv);
// get stylesheet path
nsAutoString stylePath, basePath;
aXMLDoc->getBaseURI(basePath);
getHrefFromStylesheetPI(*aXMLDoc, stylePath);
xmlDoc->getBaseURI(basePath);
getHrefFromStylesheetPI(*xmlDoc, stylePath);
txParsedURL base, ref, resolved;
base.init(basePath);
ref.init(stylePath);
base.resolve(ref, resolved);
nsRefPtr<txStylesheet> style;
nsresult rv = TX_CompileStylesheetPath(resolved, getter_AddRefs(style));
rv = TX_CompileStylesheetPath(resolved, getter_AddRefs(style));
NS_ENSURE_SUCCESS(rv, rv);
// transform
@ -206,7 +205,7 @@ txStandaloneXSLTProcessor::transform(Document* aXMLDoc, ostream& aOut,
* and prints the results to the given ostream argument
*/
nsresult
txStandaloneXSLTProcessor::transform(Document* aSource,
txStandaloneXSLTProcessor::transform(txXPathNode& aSource,
txStylesheet* aStylesheet,
ostream& aOut, ErrorObserver& aErr)
{
@ -356,7 +355,7 @@ void txStandaloneXSLTProcessor::parseStylesheetPI(const nsAFlatString& aData,
}
}
Document*
txXPathNode*
txStandaloneXSLTProcessor::parsePath(const nsACString& aPath, ErrorObserver& aErr)
{
NS_ConvertASCIItoUCS2 path(aPath);
@ -367,7 +366,7 @@ txStandaloneXSLTProcessor::parsePath(const nsACString& aPath, ErrorObserver& aEr
return 0;
}
// parse source
Document* xmlDoc;
txXPathNode* xmlDoc;
nsAutoString errors;
nsresult rv = txParseFromStream(xmlInput, path, errors, &xmlDoc);
xmlInput.close();

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

@ -122,7 +122,7 @@ public:
* @param aErr error observer
* @result NS_OK if transformation was successful
*/
nsresult transform(Document* aXMLDoc, ostream& aOut, ErrorObserver& aErr);
nsresult transform(txXPathNode& aXMLDoc, ostream& aOut, ErrorObserver& aErr);
/**
* Transform a XML document with the given stylesheet.
@ -133,7 +133,7 @@ public:
* @param aErr error observer
* @result NS_OK if transformation was successful
*/
nsresult transform(Document* aXMLDoc, txStylesheet* aXSLNode,
nsresult transform(txXPathNode& aXMLDoc, txStylesheet* aXSLNode,
ostream& aOut, ErrorObserver& aErr);
protected:
@ -160,7 +160,7 @@ protected:
* @param aErr ErrorObserver
* @result Document XML Document, or null on error
*/
static Document* parsePath(const nsACString& aPath, ErrorObserver& aErr);
static txXPathNode* parsePath(const nsACString& aPath, ErrorObserver& aErr);
};
#endif

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

@ -136,14 +136,13 @@ txStylesheet::~txStylesheet()
}
txInstruction*
txStylesheet::findTemplate(Node* aNode,
txStylesheet::findTemplate(const txXPathNode& aNode,
const txExpandedName& aMode,
txIMatchContext* aContext,
ImportFrame* aImportedBy,
ImportFrame** aImportFrame)
{
NS_ASSERTION(aImportFrame, "missing ImportFrame pointer");
NS_ASSERTION(aNode, "missing node");
*aImportFrame = nsnull;
txInstruction* matchTemplate = nsnull;
@ -195,7 +194,7 @@ txStylesheet::findTemplate(Node* aNode,
if (aMode.mLocalName) {
aMode.mLocalName->ToString(mode);
}
aNode->getNodeName(nodeName);
txXPathNodeUtils::getNodeName(aNode, nodeName);
if (matchTemplate) {
nsAutoString matchAttr;
match->toString(matchAttr);
@ -214,16 +213,16 @@ txStylesheet::findTemplate(Node* aNode,
#endif
if (!matchTemplate) {
switch(aNode->getNodeType()) {
case Node::ELEMENT_NODE :
case Node::DOCUMENT_NODE :
switch (txXPathNodeUtils::getNodeType(aNode)) {
case txXPathNodeType::ELEMENT_NODE:
case txXPathNodeType::DOCUMENT_NODE:
{
matchTemplate = mContainerTemplate;
break;
}
case Node::ATTRIBUTE_NODE :
case Node::TEXT_NODE :
case Node::CDATA_SECTION_NODE :
case txXPathNodeType::ATTRIBUTE_NODE:
case txXPathNodeType::TEXT_NODE:
case txXPathNodeType::CDATA_SECTION_NODE:
{
matchTemplate = mCharactersTemplate;
break;
@ -276,37 +275,37 @@ txStylesheet::getKeyMap()
}
PRBool
txStylesheet::isStripSpaceAllowed(Node* aNode, txIMatchContext* aContext)
txStylesheet::isStripSpaceAllowed(const txXPathNode& aNode, txIMatchContext* aContext)
{
PRInt32 frameCount = mStripSpaceTests.Count();
if (!aNode || frameCount == 0) {
if (frameCount == 0) {
return PR_FALSE;
}
switch (aNode->getNodeType()) {
case Node::ELEMENT_NODE:
{
// check Whitespace stipping handling list against given Node
PRInt32 i;
for (i = 0; i < frameCount; ++i) {
txStripSpaceTest* sst =
NS_STATIC_CAST(txStripSpaceTest*, mStripSpaceTests[i]);
if (sst->matches(aNode, aContext)) {
if (sst->stripsSpace() &&
!XMLUtils::getXMLSpacePreserve(aNode)) {
return MB_TRUE;
}
return MB_FALSE;
}
}
break;
txXPathTreeWalker walker(aNode);
PRUint16 nodeType = walker.getNodeType();
if (nodeType == txXPathNodeType::TEXT_NODE ||
nodeType == txXPathNodeType::CDATA_SECTION_NODE) {
if (!txXPathNodeUtils::isWhitespace(aNode) || !walker.moveToParent()) {
return PR_FALSE;
}
case Node::TEXT_NODE:
case Node::CDATA_SECTION_NODE:
{
if (!XMLUtils::isWhitespace(aNode))
return MB_FALSE;
return isStripSpaceAllowed(aNode->getParentNode(), aContext);
nodeType = walker.getNodeType();
}
if (nodeType != txXPathNodeType::ELEMENT_NODE) {
return PR_FALSE;
}
const txXPathNode& node = walker.getCurrentPosition();
// check Whitespace stipping handling list against given Node
PRInt32 i;
for (i = 0; i < frameCount; ++i) {
txStripSpaceTest* sst =
NS_STATIC_CAST(txStripSpaceTest*, mStripSpaceTests[i]);
if (sst->matches(node, aContext)) {
return sst->stripsSpace() && !XMLUtils::getXMLSpacePreserve(node);
}
}

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

@ -80,7 +80,7 @@ public:
return mRefCnt;
}
txInstruction* findTemplate(Node* aNode,
txInstruction* findTemplate(const txXPathNode& aNode,
const txExpandedName& aMode,
txIMatchContext* aContext,
ImportFrame* aImportedBy,
@ -91,7 +91,8 @@ public:
txOutputFormat* getOutputFormat();
GlobalVariable* getGlobalVariable(const txExpandedName& aName);
const txExpandedNameMap& getKeyMap();
PRBool isStripSpaceAllowed(Node* aNode, txIMatchContext* aContext);
PRBool isStripSpaceAllowed(const txXPathNode& aNode,
txIMatchContext* aContext);
/**
* Called by the stylesheet compiler once all stylesheets has been read.
@ -212,12 +213,12 @@ class txStripSpaceTest {
public:
txStripSpaceTest(nsIAtom* aPrefix, nsIAtom* aLocalName, PRInt32 aNSID,
MBool stripSpace)
: mNameTest(aPrefix, aLocalName, aNSID, Node::ELEMENT_NODE),
: mNameTest(aPrefix, aLocalName, aNSID, txXPathNodeType::ELEMENT_NODE),
mStrips(stripSpace)
{
}
MBool matches(Node* aNode, txIMatchContext* aContext) {
MBool matches(const txXPathNode& aNode, txIMatchContext* aContext) {
return mNameTest.matches(aNode, aContext);
}

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

@ -179,9 +179,6 @@ public:
GenerateIdFunctionCall();
TX_DECL_FUNCTION;
private:
static const char printfFmt[];
};
/**

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

@ -44,6 +44,7 @@
#include "ExprResult.h"
#include "txXSLTPatterns.h"
#include "txIXPathContext.h"
#include "txXPathTreeWalker.h"
nsresult txXSLTNumber::createNumber(Expr* aValueExpr, txPattern* aCountPattern,
txPattern* aFromPattern, LevelType aLevel,
@ -139,54 +140,54 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
txPattern* countPattern = aCountPattern;
MBool ownsCountPattern = MB_FALSE;
Node* currNode = aContext->getContextNode();
const txXPathNode& currNode = aContext->getContextNode();
// Parse count- and from-attributes
if (!aCountPattern) {
ownsCountPattern = MB_TRUE;
txNodeTest* nodeTest = 0;
switch (currNode->getNodeType()) {
case Node::ELEMENT_NODE:
switch (txXPathNodeUtils::getNodeType(currNode)) {
case txXPathNodeType::ELEMENT_NODE:
{
nsCOMPtr<nsIAtom> localName;
currNode->getLocalName(getter_AddRefs(localName));
nodeTest = new txNameTest(0, localName,
currNode->getNamespaceID(),
Node::ELEMENT_NODE);
nsCOMPtr<nsIAtom> localName =
txXPathNodeUtils::getLocalName(currNode);
PRInt32 namespaceID = txXPathNodeUtils::getNamespaceID(currNode);
nodeTest = new txNameTest(0, localName, namespaceID,
txXPathNodeType::ELEMENT_NODE);
break;
}
case Node::TEXT_NODE:
case Node::CDATA_SECTION_NODE:
case txXPathNodeType::TEXT_NODE:
case txXPathNodeType::CDATA_SECTION_NODE:
{
nodeTest = new txNodeTypeTest(txNodeTypeTest::TEXT_TYPE);
break;
}
case Node::PROCESSING_INSTRUCTION_NODE:
case txXPathNodeType::PROCESSING_INSTRUCTION_NODE:
{
txNodeTypeTest* typeTest;
typeTest = new txNodeTypeTest(txNodeTypeTest::PI_TYPE);
if (typeTest) {
nsAutoString nodeName;
currNode->getNodeName(nodeName);
txXPathNodeUtils::getNodeName(currNode, nodeName);
typeTest->setNodeName(nodeName);
}
nodeTest = typeTest;
break;
}
case Node::COMMENT_NODE:
case txXPathNodeType::COMMENT_NODE:
{
nodeTest = new txNodeTypeTest(txNodeTypeTest::COMMENT_TYPE);
break;
}
case Node::DOCUMENT_NODE:
case Node::ATTRIBUTE_NODE:
case txXPathNodeType::DOCUMENT_NODE:
case txXPathNodeType::ATTRIBUTE_NODE:
default:
{
// this won't match anything as we walk up the tree
// but it's what the spec says to do
nodeTest = new txNameTest(0, txXPathAtoms::_asterix, 0,
(Node::NodeType)currNode->getNodeType());
txXPathNodeUtils::getNodeType(currNode));
break;
}
}
@ -205,36 +206,33 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
// level = "single"
if (aLevel == eLevelSingle) {
Node* node = currNode;
while (node) {
if (aFromPattern && node != currNode &&
aFromPattern->matches(node, aContext)) {
txXPathTreeWalker walker(currNode);
do {
if (aFromPattern && !walker.isOnNode(currNode) &&
aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
break;
}
if (countPattern->matches(node, aContext)) {
aValues.add(NS_INT32_TO_PTR(getSiblingCount(node, countPattern,
if (countPattern->matches(walker.getCurrentPosition(), aContext)) {
aValues.add(NS_INT32_TO_PTR(getSiblingCount(walker, countPattern,
aContext)));
break;
}
node = node->getXPathParent();
}
} while (walker.moveToParent());
// Spec says to only match ancestors that are decendants of the
// ancestor that matches the from-pattern, so keep going to make
// sure that there is an ancestor that does.
if (aFromPattern && aValues.getLength()) {
node = node->getXPathParent();
while (node) {
if (aFromPattern->matches(node, aContext)) {
PRBool hasParent;
while ((hasParent = walker.moveToParent())) {
if (aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
break;
}
node = node->getXPathParent();
}
if (!node) {
if (!hasParent) {
aValues.clear();
}
}
@ -242,23 +240,21 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
// level = "multiple"
else if (aLevel == eLevelMultiple) {
// find all ancestor-or-selfs that matches count until...
Node* node = currNode;
txXPathTreeWalker walker(currNode);
MBool matchedFrom = MB_FALSE;
while (node) {
if (aFromPattern && node != currNode &&
aFromPattern->matches(node, aContext)) {
do {
if (aFromPattern && !walker.isOnNode(currNode) &&
aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
//... we find one that matches from
matchedFrom = MB_TRUE;
break;
}
if (countPattern->matches(node, aContext)) {
aValues.add(NS_INT32_TO_PTR(getSiblingCount(node, countPattern,
if (countPattern->matches(walker.getCurrentPosition(), aContext)) {
aValues.add(NS_INT32_TO_PTR(getSiblingCount(walker, countPattern,
aContext)));
}
node = node->getXPathParent();
}
} while (walker.moveToParent());
// Spec says to only match ancestors that are decendants of the
// ancestor that matches the from-pattern, so if none did then
@ -269,23 +265,22 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
}
// level = "any"
else if (aLevel == eLevelAny) {
Node* node = currNode;
PRInt32 value = 0;
MBool matchedFrom = MB_FALSE;
while (node) {
if (aFromPattern && node != currNode &&
aFromPattern->matches(node, aContext)) {
txXPathTreeWalker walker(currNode);
do {
if (aFromPattern && !walker.isOnNode(currNode) &&
aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
matchedFrom = MB_TRUE;
break;
}
if (countPattern->matches(node, aContext)) {
if (countPattern->matches(walker.getCurrentPosition(), aContext)) {
++value;
}
node = getPrevInDocumentOrder(node);
}
} while (getPrevInDocumentOrder(walker));
// Spec says to only count nodes that follows the first node that
// matches the from pattern. So so if none did then we shouldn't
@ -439,34 +434,29 @@ txXSLTNumber::getCounters(Expr* aGroupSize, Expr* aGroupSeparator,
}
PRInt32
txXSLTNumber::getSiblingCount(Node* aNode, txPattern* aCountPattern,
txXSLTNumber::getSiblingCount(txXPathTreeWalker& aWalker,
txPattern* aCountPattern,
txIMatchContext* aContext)
{
PRInt32 value = 1;
Node* node = aNode->getPreviousSibling();
while (node) {
if (aCountPattern->matches(node, aContext)) {
while (aWalker.moveToPreviousSibling()) {
if (aCountPattern->matches(aWalker.getCurrentPosition(), aContext)) {
++value;
}
node = node->getPreviousSibling();
}
return value;
}
Node*
txXSLTNumber::getPrevInDocumentOrder(Node* aNode)
PRBool
txXSLTNumber::getPrevInDocumentOrder(txXPathTreeWalker& aWalker)
{
Node* prev = aNode->getPreviousSibling();
if (prev) {
Node* lastChild = prev->getLastChild();
while (lastChild) {
prev = lastChild;
lastChild = prev->getLastChild();
if (aWalker.moveToPreviousSibling()) {
while (aWalker.moveToLastChild()) {
// do nothing
}
return prev;
return PR_TRUE;
}
return aNode->getXPathParent();
return aWalker.moveToParent();
}
#define TX_CHAR_RANGE(ch, a, b) if (ch < a) return MB_FALSE; \

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

@ -44,10 +44,10 @@
#include "nsString.h"
class Expr;
class Node;
class txPattern;
class txIEvalContext;
class txIMatchContext;
class txXPathTreeWalker;
class txXSLTNumber {
public:
@ -74,11 +74,17 @@ private:
txList& aCounters, nsAString& aHead,
nsAString& aTail);
static PRInt32 getSiblingCount(Node* aNode, txPattern* aCountPattern,
/**
* getSiblingCount uses aWalker to walk the siblings of aWalker's current
* position.
*
*/
static PRInt32 getSiblingCount(txXPathTreeWalker& aWalker,
txPattern* aCountPattern,
txIMatchContext* aContext);
static Node* getPrevInDocumentOrder(Node* aNode);
static PRBool getPrevInDocumentOrder(txXPathTreeWalker& aWalker);
static MBool isAlphaNumeric(PRUnichar ch);
};

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

@ -108,7 +108,7 @@ double txUnionPattern::getDefaultPriority()
* This should be called on the simple patterns for xsl:template,
* but is fine for xsl:key and xsl:number
*/
MBool txUnionPattern::matches(Node* aNode, txIMatchContext* aContext)
MBool txUnionPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
{
txListIterator iter(&mLocPathPatterns);
while (iter.hasNext()) {
@ -182,9 +182,9 @@ nsresult txLocPathPattern::addStep(txPattern* aPattern, MBool isChild)
return NS_OK;
}
MBool txLocPathPattern::matches(Node* aNode, txIMatchContext* aContext)
MBool txLocPathPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
{
NS_ASSERTION(aNode && mSteps.getLength(), "Internal error");
NS_ASSERTION(mSteps.getLength(), "Internal error");
/*
* The idea is to split up a path into blocks separated by descendant
@ -205,40 +205,42 @@ MBool txLocPathPattern::matches(Node* aNode, txIMatchContext* aContext)
step = (Step*)iter.previous();
if (!step->pattern->matches(aNode, aContext))
return MB_FALSE;
Node* node = aNode->getXPathParent();
txXPathTreeWalker walker(aNode);
PRBool hasParent = walker.moveToParent();
while (step->isChild) {
step = (Step*)iter.previous();
if (!step)
return MB_TRUE; // all steps matched
if (!node || !step->pattern->matches(node, aContext))
if (!hasParent || !step->pattern->matches(walker.getCurrentPosition(), aContext))
return MB_FALSE; // no more ancestors or no match
node = node->getXPathParent();
hasParent = walker.moveToParent();
}
// We have at least one // path separator
Node *blockStart = node;
txXPathTreeWalker blockWalker(walker);
txListIterator blockIter(iter);
while ((step = (Step*)iter.previous())) {
if (!node)
if (!hasParent)
return MB_FALSE; // There are more steps in the current block
// than ancestors of the tested node
if (!step->pattern->matches(node, aContext)) {
if (!step->pattern->matches(walker.getCurrentPosition(), aContext)) {
// Didn't match. We restart at beginning of block using a new
// start node
iter = blockIter;
blockStart = blockStart->getXPathParent();
node = blockStart;
hasParent = blockWalker.moveToParent();
walker.moveTo(blockWalker);
}
else {
node = node->getXPathParent();
hasParent = walker.moveToParent();
if (!step->isChild) {
// We've matched an entire block. Set new start iter and start node
blockIter = iter;
blockStart = node;
blockWalker.moveTo(walker);
}
}
}
@ -288,9 +290,9 @@ txRootPattern::~txRootPattern()
{
}
MBool txRootPattern::matches(Node* aNode, txIMatchContext* aContext)
MBool txRootPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
{
return aNode && (aNode->getNodeType() == Node::DOCUMENT_NODE);
return (txXPathNodeUtils::getNodeType(aNode) == txXPathNodeType::DOCUMENT_NODE);
}
double txRootPattern::getDefaultPriority()
@ -339,19 +341,23 @@ txIdPattern::~txIdPattern()
{
}
MBool txIdPattern::matches(Node* aNode, txIMatchContext* aContext)
MBool txIdPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
{
if (aNode->getNodeType() != Node::ELEMENT_NODE) {
if (txXPathNodeUtils::getNodeType(aNode) != txXPathNodeType::ELEMENT_NODE) {
return MB_FALSE;
}
// Get a ID attribute, if there is
nsAutoString value;
#ifdef TX_EXE
if (!((Element*)aNode)->getIDValue(value))
return MB_FALSE;
Element* elem;
nsresult rv = txXPathNativeNode::getElement(aNode, &elem);
NS_ASSERTION(NS_SUCCEEDED(rv), "So why claim it's an element above?");
if (!elem->getIDValue(value)) {
return PR_FALSE;
}
#else
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode->getNSObj());
nsIContent* content = txXPathNativeNode::getContent(aNode);
NS_ASSERTION(content, "a Element without nsIContent");
if (!content) {
return MB_FALSE;
@ -405,16 +411,14 @@ txKeyPattern::~txKeyPattern()
{
}
MBool txKeyPattern::matches(Node* aNode, txIMatchContext* aContext)
MBool txKeyPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
{
txExecutionState* es = (txExecutionState*)aContext->getPrivateContext();
Document* contextDoc;
if (aNode->getNodeType() == Node::DOCUMENT_NODE)
contextDoc = (Document*)aNode;
else
contextDoc = aNode->getOwnerDocument();
nsAutoPtr<txXPathNode> contextDoc(txXPathNodeUtils::getOwnerDocument(aNode));
NS_ENSURE_TRUE(contextDoc, PR_FALSE);
nsRefPtr<txNodeSet> nodes;
nsresult rv = es->getKeyNodes(mName, contextDoc, mValue, PR_TRUE,
nsresult rv = es->getKeyNodes(mName, *contextDoc, mValue, PR_TRUE,
getter_AddRefs(nodes));
NS_ENSURE_SUCCESS(rv, PR_FALSE);
@ -459,17 +463,18 @@ txStepPattern::~txStepPattern()
delete mNodeTest;
}
MBool txStepPattern::matches(Node* aNode, txIMatchContext* aContext)
MBool txStepPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
{
NS_ASSERTION(mNodeTest && aNode, "Internal error");
if (!aNode)
return MB_FALSE;
NS_ASSERTION(mNodeTest, "Internal error");
if (!mNodeTest->matches(aNode, aContext))
return MB_FALSE;
if (!mIsAttr && !aNode->getParentNode())
txXPathTreeWalker walker(aNode);
if ((!mIsAttr && walker.getNodeType() == txXPathNodeType::ATTRIBUTE_NODE) ||
!walker.moveToParent()) {
return MB_FALSE;
}
if (isEmpty()) {
return MB_TRUE;
}
@ -497,25 +502,14 @@ MBool txStepPattern::matches(Node* aNode, txIMatchContext* aContext)
nsresult rv = aContext->recycler()->getNodeSet(getter_AddRefs(nodes));
NS_ENSURE_SUCCESS(rv, rv);
Node* parent = aNode->getXPathParent();
if (mIsAttr) {
NamedNodeMap* atts = parent->getAttributes();
if (atts) {
PRUint32 i;
for (i = 0; i < atts->getLength(); i++) {
Node* attr = atts->item(i);
if (mNodeTest->matches(attr, aContext))
nodes->append(attr);
}
}
}
else {
Node* tmpNode = parent->getFirstChild();
while (tmpNode) {
if (mNodeTest->matches(tmpNode, aContext))
nodes->append(tmpNode);
tmpNode = tmpNode->getNextSibling();
PRBool hasNext = mIsAttr ? walker.moveToFirstAttribute() :
walker.moveToFirstChild();
while (hasNext) {
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
nodes->append(walker.getCurrentPosition());
}
hasNext = mIsAttr ? walker.moveToNextAttribute() :
walker.moveToNextSibling();
}
txListIterator iter(&predicates);
@ -539,7 +533,7 @@ MBool txStepPattern::matches(Node* aNode, txIMatchContext* aContext)
// handle default, [position() == numberValue()]
if ((double)predContext.position() ==
exprResult->numberValue()) {
Node* tmp = predContext.getContextNode();
const txXPathNode& tmp = predContext.getContextNode();
if (tmp == aNode)
contextIsInPredicate = MB_TRUE;
newNodes->append(tmp);
@ -547,7 +541,7 @@ MBool txStepPattern::matches(Node* aNode, txIMatchContext* aContext)
break;
default:
if (exprResult->booleanValue()) {
Node* tmp = predContext.getContextNode();
const txXPathNode& tmp = predContext.getContextNode();
if (tmp == aNode)
contextIsInPredicate = MB_TRUE;
newNodes->append(tmp);
@ -557,7 +551,7 @@ MBool txStepPattern::matches(Node* aNode, txIMatchContext* aContext)
}
// Move new NodeSet to the current one
nodes->clear();
nodes->append(newNodes);
nodes->append(*newNodes);
if (!contextIsInPredicate) {
return MB_FALSE;
}

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

@ -53,7 +53,8 @@ public:
/*
* Determines whether this Pattern matches the given node.
*/
virtual MBool matches(Node* aNode, txIMatchContext* aContext) = 0;
virtual MBool matches(const txXPathNode& aNode,
txIMatchContext* aContext) = 0;
/*
* Returns the default priority of this Pattern.
@ -85,7 +86,7 @@ public:
};
#define TX_DECL_PATTERN \
MBool matches(Node* aNode, txIMatchContext* aContext); \
MBool matches(const txXPathNode& aNode, txIMatchContext* aContext); \
double getDefaultPriority(); \
void toString(nsAString& aDest)
#define TX_DECL_PATTERN2 \