Bug 333098: Support XPath and XSLT on orphaned subtrees

This commit is contained in:
cvshook%sicking.cc 2006-09-26 00:04:14 +00:00
Родитель 7ed87fbcba
Коммит ad13a4b79e
11 изменённых файлов: 146 добавлений и 123 удалений

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

@ -726,7 +726,7 @@ txCoreFunctionCall::isSensitiveTo(ContextSensitivity aContext)
}
case ID:
{
return (aContext & DOCUMENT_CONTEXT) ||
return (aContext & NODE_CONTEXT) ||
argsSensitiveTo(aContext);
}
case LAST:

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

@ -122,14 +122,12 @@ public:
typedef PRUint16 ContextSensitivity;
enum {
NO_CONTEXT = 0x00,
DOCUMENT_CONTEXT = 0x01,
NODE_ONLY_CONTEXT = 0x02,
NODE_CONTEXT = DOCUMENT_CONTEXT | NODE_ONLY_CONTEXT,
POSITION_CONTEXT = 0x04,
SIZE_CONTEXT = 0x08,
NODE_CONTEXT = 0x01,
POSITION_CONTEXT = 0x02,
SIZE_CONTEXT = 0x04,
NODESET_CONTEXT = POSITION_CONTEXT | SIZE_CONTEXT,
VARIABLES_CONTEXT = 0x10,
PRIVATE_CONTEXT = 0x20,
VARIABLES_CONTEXT = 0x08,
PRIVATE_CONTEXT = 0x10,
ANY_CONTEXT = 0xFFFF
};

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

@ -73,30 +73,71 @@ txXPathTreeWalker::~txXPathTreeWalker()
{
}
void
txXPathTreeWalker::moveToRoot()
{
if (mPosition.isDocument()) {
return;
}
nsIDocument* root = mPosition.mContent->GetCurrentDoc();
if (root) {
mPosition.mIndex = txXPathNode::eDocument;
mPosition.mDocument = root;
}
else {
nsIContent *parent, *current = mPosition.mContent;
while ((parent = current->GetParent())) {
current = parent;
}
mPosition.mIndex = txXPathNode::eContent;
mPosition.mContent = current;
}
mCurrentIndex = kUnknownIndex;
mDescendants.Clear();
}
PRBool
txXPathTreeWalker::moveToElementById(const nsAString& aID)
{
nsCOMPtr<nsIDOMDocument> document;
if (aID.IsEmpty()) {
return PR_FALSE;
}
nsIDocument* doc;
if (mPosition.isDocument()) {
document = do_QueryInterface(mPosition.mDocument);
doc = mPosition.mDocument;
}
else {
document = do_QueryInterface(mPosition.mContent->GetDocument());
doc = mPosition.mContent->GetCurrentDoc();
}
if (!document) {
nsCOMPtr<nsIContent> content;
if (doc) {
nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(doc);
NS_ASSERTION(document, "QI failed");
nsCOMPtr<nsIDOMElement> element;
document->GetElementById(aID, getter_AddRefs(element));
content = do_QueryInterface(element);
}
else {
// We're in a disconnected subtree, search only that subtree.
nsIContent *parent, *current = mPosition.mContent;
while ((parent = current->GetParent())) {
current = parent;
}
content = nsContentUtils::MatchElementId(current, aID);
}
if (!content) {
return PR_FALSE;
}
nsCOMPtr<nsIDOMElement> element;
document->GetElementById(aID, getter_AddRefs(element));
if (!element) {
return PR_FALSE;
}
nsCOMPtr<nsIContent> content = do_QueryInterface(element);
NS_ENSURE_TRUE(content, PR_FALSE);
mPosition.mIndex = txXPathNode::eContent;
mPosition.mContent = content;
mCurrentIndex = kUnknownIndex;
@ -676,19 +717,22 @@ txXPathNodeUtils::comparePosition(const txXPathNode& aNode,
// Get document for both nodes.
nsIDocument* document = aNode.isDocument() ?
aNode.mDocument :
aNode.mContent->GetDocument();
aNode.mContent->GetCurrentDoc();
nsIDocument* otherDocument = aOtherNode.isDocument() ?
aOtherNode.mDocument :
aOtherNode.mContent->GetDocument();
aOtherNode.mContent->GetCurrentDoc();
// If the nodes have different ownerdocuments, compare the document
// If the nodes have different current documents, compare the document
// pointers.
if (document && otherDocument && document != otherDocument) {
return document > otherDocument ? 1 : -1;
if (document != otherDocument) {
return document < otherDocument ? -1 : 1;
}
// Every node comes after its ownerdocument.
// Now either both nodes are in orphan trees, or they are both in the
// same tree.
// Every node comes after its current document.
if (aNode.isDocument()) {
return -1;
}
@ -714,21 +758,14 @@ txXPathNodeUtils::comparePosition(const txXPathNode& aNode,
otherIndex = (PRUint32)parent->IndexOf(otherContent);
}
else {
if (!document) {
if (!otherDocument) {
// Neither aNode nor aOtherNode are not in a document,
// compare their top ancestors.
return content > otherContent ? 1 : -1;
}
// since document == otherDocument either both content and
// otherContent are root nodes in respective orphan tree, or
// both are direct children of the same document.
// aNode is not in the tree, compare its top ancestor with
// aOtherNode's document.
return (void*)content > (void*)otherDocument ? 1 : -1;
}
else if (!otherDocument) {
// aOtherNode is not in a document, compare its top
// ancestor with aNode's document.
return (void*)document > (void*)otherContent ? 1 : -1;
if (!document) {
// Both are roots in orphan trees.
return content < otherContent ? -1 : 1;
}
// Both nodes are in the same document.
@ -754,25 +791,6 @@ txXPathNodeUtils::comparePosition(const txXPathNode& aNode,
otherContent = otherContent->GetParent();
}
if (!document) {
if (!otherDocument) {
// Neither aNode nor aOtherNode are not in a document, compare
// their top ancestors.
return parents.ElementAt(parents.Count() - 1) >
otherParents.ElementAt(otherParents.Count() - 1) ? 1 : -1;
}
// aNode is not in the tree, compare its top ancestor with aOtherNode's
// document.
return parents.ElementAt(parents.Count() - 1) > otherDocument ? 1 : -1;
}
else if (!otherDocument) {
// aOtherNode is not in a document, compare its top
// ancestor with aNode's document.
return document >
otherParents.ElementAt(otherParents.Count() - 1) ? 1 : -1;
}
// Walk back down along the parent-chains until we find where they split.
PRInt32 total = parents.Count() - 1;
PRInt32 otherTotal = otherParents.Count() - 1;
@ -790,10 +808,15 @@ txXPathNodeUtils::comparePosition(const txXPathNode& aNode,
index = (PRUint32)parent->IndexOf(content);
otherIndex = (PRUint32)parent->IndexOf(otherContent);
}
else {
else if (document) {
index = (PRUint32)document->IndexOf(content);
otherIndex = (PRUint32)document->IndexOf(otherContent);
}
else {
// The two nodes are in different orphan subtrees.
NS_ASSERTION(i == 0, "this shouldn't happen");
return content < otherContent ? -1 : 1;
}
NS_ASSERTION(index != otherIndex && index >= 0 && otherIndex >= 0,
"invalid index in compareTreePosition");
return index < otherIndex ? -1 : 1;

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

@ -51,29 +51,19 @@
nsresult
RootExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
{
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(*document, aResult);
} //-- evaluate
txXPathTreeWalker walker(aContext->getContextNode());
walker.moveToRoot();
return aContext->recycler()->getNodeSet(walker.getCurrentPosition(),
aResult);
}
TX_IMPL_EXPR_STUBS_0(RootExpr, NODESET_RESULT)
PRBool
RootExpr::isSensitiveTo(ContextSensitivity aContext)
{
return !!(aContext & DOCUMENT_CONTEXT);
return !!(aContext & NODE_CONTEXT);
}
#ifdef TX_TO_STRING

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

@ -59,6 +59,14 @@ txXPathTreeWalker::~txXPathTreeWalker()
#define INNER mPosition.mInner
void
txXPathTreeWalker::moveToRoot()
{
if (INNER->nodeType != Node::DOCUMENT_NODE) {
INNER = INNER->ownerDocument;
}
}
PRBool
txXPathTreeWalker::moveToElementById(const nsAString& aID)
{

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

@ -83,6 +83,7 @@ public:
void moveTo(const txXPathTreeWalker& aWalker);
void moveToRoot();
PRBool moveToParent();
PRBool moveToElementById(const nsAString& aID);
PRBool moveToFirstAttribute();
@ -236,8 +237,8 @@ txXPathNodeUtils::getUniqueIdentifier(const txXPathNode& aNode)
#ifdef TX_EXE
return NS_PTR_TO_INT32(aNode.mInner);
#else
NS_PRECONDITION(aNode.mIndex == txXPathNode::eDocument,
"Only implemented for documents.");
NS_PRECONDITION(!aNode.isAttribute(),
"Not implemented for attributes.");
return NS_PTR_TO_INT32(aNode.mDocument);
#endif
}
@ -282,7 +283,8 @@ txXPathNodeUtils::isRoot(const txXPathNode& aNode)
#ifdef TX_EXE
return aNode.mInner->getNodeType() == Node::DOCUMENT_NODE;
#else
return aNode.isDocument();
return aNode.isDocument() ||
(aNode.isContent() && !aNode.mContent->GetNodeParent());
#endif
}

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

@ -500,12 +500,12 @@ txExecutionState::retrieveDocument(const nsAString& aUri)
nsresult
txExecutionState::getKeyNodes(const txExpandedName& aKeyName,
const txXPathNode& aDocument,
const txXPathNode& aRoot,
const nsAString& aKeyValue,
PRBool aIndexIfNotFound,
txNodeSet** aResult)
{
return mKeyHash.getKeyNodes(aKeyName, aDocument, aKeyValue,
return mKeyHash.getKeyNodes(aKeyName, aRoot, aKeyValue,
aIndexIfNotFound, *this, aResult);
}

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

@ -131,7 +131,7 @@ public:
txExpandedNameMap* getParamMap();
const txXPathNode* retrieveDocument(const nsAString& aUri);
nsresult getKeyNodes(const txExpandedName& aKeyName,
const txXPathNode& aDocument,
const txXPathNode& aRoot,
const nsAString& aKeyValue, PRBool aIndexIfNotFound,
txNodeSet** aResult);
TemplateRule* getCurrentTemplateRule();

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

@ -53,17 +53,17 @@ class txKeyValueHashKey
{
public:
txKeyValueHashKey(const txExpandedName& aKeyName,
PRInt32 aDocumentIdentifier,
PRInt32 aRootIdentifier,
const nsAString& aKeyValue)
: mKeyName(aKeyName),
mKeyValue(aKeyValue),
mDocumentIdentifier(aDocumentIdentifier)
mRootIdentifier(aRootIdentifier)
{
}
txExpandedName mKeyName;
nsString mKeyValue;
PRInt32 mDocumentIdentifier;
PRInt32 mRootIdentifier;
};
struct txKeyValueHashEntry : public PLDHashEntryHdr
@ -89,14 +89,14 @@ class txIndexedKeyHashKey
{
public:
txIndexedKeyHashKey(txExpandedName aKeyName,
PRInt32 aDocumentIdentifier)
PRInt32 aRootIdentifier)
: mKeyName(aKeyName),
mDocumentIdentifier(aDocumentIdentifier)
mRootIdentifier(aRootIdentifier)
{
}
txExpandedName mKeyName;
PRInt32 mDocumentIdentifier;
PRInt32 mRootIdentifier;
};
struct txIndexedKeyHashEntry : public PLDHashEntryHdr
@ -140,14 +140,14 @@ public:
PRBool addKey(nsAutoPtr<txPattern> aMatch, nsAutoPtr<Expr> aUse);
/**
* Indexes a document and adds it to the hash of key values
* @param aDocument Document to index and add
* Indexes a subtree and adds it to the hash of key values
* @param aRoot Subtree root to index and add
* @param aKeyValueHash Hash to add values to
* @param aEs txExecutionState to use for XPath evaluation
*/
nsresult indexDocument(const txXPathNode& aDocument,
txKeyValueHash& aKeyValueHash,
txExecutionState& aEs);
nsresult indexSubtreeRoot(const txXPathNode& aRoot,
txKeyValueHash& aKeyValueHash,
txExecutionState& aEs);
private:
/**
@ -203,7 +203,7 @@ public:
nsresult init();
nsresult getKeyNodes(const txExpandedName& aKeyName,
const txXPathNode& aDocument,
const txXPathNode& aRoot,
const nsAString& aKeyValue,
PRBool aIndexIfNotFound,
txExecutionState& aEs,
@ -213,7 +213,7 @@ private:
// Hash of all indexed key-values
txKeyValueHash mKeyValues;
// Hash showing which keys+documents has been indexed
// Hash showing which keys+roots has been indexed
txIndexedKeyHash mIndexedKeys;
// Map of txXSLKeys

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

@ -90,8 +90,8 @@ txKeyFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
rv = ((Expr*)iter.next())->evaluate(aContext, getter_AddRefs(exprResult));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txXPathNode> contextDoc(txXPathNodeUtils::getOwnerDocument(aContext->getContextNode()));
NS_ENSURE_TRUE(contextDoc, NS_ERROR_FAILURE);
txXPathTreeWalker walker(aContext->getContextNode());
walker.moveToRoot();
nsRefPtr<txNodeSet> res;
txNodeSet* nodeSet;
@ -108,8 +108,8 @@ txKeyFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
txXPathNodeUtils::appendNodeValue(nodeSet->get(i), val);
nsRefPtr<txNodeSet> nodes;
rv = es->getKeyNodes(keyName, *contextDoc, val, i == 0,
getter_AddRefs(nodes));
rv = es->getKeyNodes(keyName, walker.getCurrentPosition(), val,
i == 0, getter_AddRefs(nodes));
NS_ENSURE_SUCCESS(rv, rv);
res->add(*nodes);
@ -118,8 +118,8 @@ txKeyFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
else {
nsAutoString val;
exprResult->stringValue(val);
rv = es->getKeyNodes(keyName, *contextDoc, val, PR_TRUE,
getter_AddRefs(res));
rv = es->getKeyNodes(keyName, walker.getCurrentPosition(), val,
PR_TRUE, getter_AddRefs(res));
NS_ENSURE_SUCCESS(rv, rv);
}
@ -138,7 +138,7 @@ txKeyFunctionCall::getReturnType()
PRBool
txKeyFunctionCall::isSensitiveTo(ContextSensitivity aContext)
{
return (aContext & DOCUMENT_CONTEXT) || argsSensitiveTo(aContext);
return (aContext & NODE_CONTEXT) || argsSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
@ -171,7 +171,7 @@ txKeyValueHashEntry::MatchEntry(const void* aKey) const
NS_STATIC_CAST(const txKeyValueHashKey*, aKey);
return mKey.mKeyName == key->mKeyName &&
mKey.mDocumentIdentifier == key->mDocumentIdentifier &&
mKey.mRootIdentifier == key->mRootIdentifier &&
mKey.mKeyValue.Equals(key->mKeyValue);
}
@ -183,7 +183,7 @@ txKeyValueHashEntry::HashKey(const void* aKey)
return key->mKeyName.mNamespaceID ^
NS_PTR_TO_INT32(key->mKeyName.mLocalName.get()) ^
key->mDocumentIdentifier ^
key->mRootIdentifier ^
HashString(key->mKeyValue);
}
@ -200,7 +200,7 @@ txIndexedKeyHashEntry::MatchEntry(const void* aKey) const
NS_STATIC_CAST(const txIndexedKeyHashKey*, aKey);
return mKey.mKeyName == key->mKeyName &&
mKey.mDocumentIdentifier == key->mDocumentIdentifier;
mKey.mRootIdentifier == key->mRootIdentifier;
}
PLDHashNumber
@ -211,7 +211,7 @@ txIndexedKeyHashEntry::HashKey(const void* aKey)
return key->mKeyName.mNamespaceID ^
NS_PTR_TO_INT32(key->mKeyName.mLocalName.get()) ^
key->mDocumentIdentifier;
key->mRootIdentifier;
}
/*
@ -220,7 +220,7 @@ txIndexedKeyHashEntry::HashKey(const void* aKey)
nsresult
txKeyHash::getKeyNodes(const txExpandedName& aKeyName,
const txXPathNode& aDocument,
const txXPathNode& aRoot,
const nsAString& aKeyValue,
PRBool aIndexIfNotFound,
txExecutionState& aEs,
@ -231,7 +231,7 @@ txKeyHash::getKeyNodes(const txExpandedName& aKeyName,
*aResult = nsnull;
PRInt32 identifier = txXPathNodeUtils::getUniqueIdentifier(aDocument);
PRInt32 identifier = txXPathNodeUtils::getUniqueIdentifier(aRoot);
txKeyValueHashKey valueKey(aKeyName, identifier, aKeyValue);
txKeyValueHashEntry* valueEntry = mKeyValues.GetEntry(valueKey);
@ -275,7 +275,7 @@ txKeyHash::getKeyNodes(const txExpandedName& aKeyName,
return NS_ERROR_INVALID_ARG;
}
nsresult rv = xslKey->indexDocument(aDocument, mKeyValues, aEs);
nsresult rv = xslKey->indexSubtreeRoot(aRoot, mKeyValues, aEs);
NS_ENSURE_SUCCESS(rv, rv);
indexEntry->mIndexed = PR_TRUE;
@ -349,18 +349,18 @@ PRBool txXSLKey::addKey(nsAutoPtr<txPattern> aMatch, nsAutoPtr<Expr> aUse)
/**
* Indexes a document and adds it to the hash of key values
* @param aDocument Document to index and add
* @param aRoot Subtree root to index and add
* @param aKeyValueHash Hash to add values to
* @param aEs txExecutionState to use for XPath evaluation
*/
nsresult txXSLKey::indexDocument(const txXPathNode& aDocument,
txKeyValueHash& aKeyValueHash,
txExecutionState& aEs)
nsresult txXSLKey::indexSubtreeRoot(const txXPathNode& aRoot,
txKeyValueHash& aKeyValueHash,
txExecutionState& aEs)
{
txKeyValueHashKey key(mName,
txXPathNodeUtils::getUniqueIdentifier(aDocument),
txXPathNodeUtils::getUniqueIdentifier(aRoot),
EmptyString());
return indexTree(aDocument, key, aKeyValueHash, aEs);
return indexTree(aRoot, key, aKeyValueHash, aEs);
}
/**

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

@ -215,14 +215,16 @@ txStylesheet::findTemplate(const txXPathNode& aNode,
#endif
if (!matchTemplate) {
if (txXPathNodeUtils::isElement(aNode) ||
txXPathNodeUtils::isRoot(aNode)) {
matchTemplate = mContainerTemplate;
}
else if (txXPathNodeUtils::isAttribute(aNode) ||
txXPathNodeUtils::isText(aNode)) {
// Test for these first since a node can be both a text node
// and a root (if it is orphaned)
if (txXPathNodeUtils::isAttribute(aNode) ||
txXPathNodeUtils::isText(aNode)) {
matchTemplate = mCharactersTemplate;
}
else if (txXPathNodeUtils::isElement(aNode) ||
txXPathNodeUtils::isRoot(aNode)) {
matchTemplate = mContainerTemplate;
}
else {
matchTemplate = mEmptyTemplate;
}