/** * Selects from the descendants of the context node * all nodes that match the Expr **/ nsresult PathExpr::evalDescendants(Expr* aStep, const txXPathNode& aNode, txIMatchContext* aContext, txNodeSet* resNodes) { txSingleNodeContext eContext(aNode, aContext); nsRefPtr<txAExprResult> res; nsresult rv = aStep->evaluate(&eContext, getter_AddRefs(res)); NS_ENSURE_SUCCESS(rv, rv); if (res->getResultType() != txAExprResult::NODESET) { //XXX ErrorReport: report nonnodeset error return NS_ERROR_XSLT_NODESET_EXPECTED; } txNodeSet* oldSet = static_cast<txNodeSet*> (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); txXPathTreeWalker walker(aNode); if (!walker.moveToFirstChild()) { return NS_OK; } do { const txXPathNode& node = walker.getCurrentPosition(); if (!(filterWS && txXPathNodeUtils::isText(node) && txXPathNodeUtils::isWhitespace(node))) { rv = evalDescendants(aStep, node, aContext, resNodes); NS_ENSURE_SUCCESS(rv, rv); } } while (walker.moveToNextSibling()); return NS_OK; } //-- evalDescendants
already_AddRefed<XPathResult> XPathExpression::EvaluateWithContext(nsINode& aContextNode, uint32_t aContextPosition, uint32_t aContextSize, uint16_t aType, XPathResult* aInResult, ErrorResult& aRv) { if (aContextPosition > aContextSize) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } if (!nsContentUtils::LegacyIsCallerNativeCode() && !nsContentUtils::CanCallerAccess(&aContextNode)) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return nullptr; } if (mCheckDocument) { nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument); if (doc != aContextNode.OwnerDoc()) { aRv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR); return nullptr; } } uint16_t nodeType = aContextNode.NodeType(); if (nodeType == nsIDOMNode::TEXT_NODE || nodeType == nsIDOMNode::CDATA_SECTION_NODE) { nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(&aContextNode); if (!textNode) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } uint32_t textLength; textNode->GetLength(&textLength); if (textLength == 0) { aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return nullptr; } // XXX Need to get logical XPath text node for CDATASection // and Text nodes. } else if (nodeType != nsIDOMNode::DOCUMENT_NODE && nodeType != nsIDOMNode::ELEMENT_NODE && nodeType != nsIDOMNode::ATTRIBUTE_NODE && nodeType != nsIDOMNode::COMMENT_NODE && nodeType != nsIDOMNode::PROCESSING_INSTRUCTION_NODE) { aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return nullptr; } nsAutoPtr<txXPathNode> contextNode(txXPathNativeNode::createXPathNode(&aContextNode)); if (!contextNode) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } EvalContextImpl eContext(*contextNode, aContextPosition, aContextSize, mRecycler); RefPtr<txAExprResult> exprResult; aRv = mExpression->evaluate(&eContext, getter_AddRefs(exprResult)); if (aRv.Failed()) { return nullptr; } uint16_t resultType = aType; if (aType == XPathResult::ANY_TYPE) { short exprResultType = exprResult->getResultType(); switch (exprResultType) { case txAExprResult::NUMBER: resultType = XPathResult::NUMBER_TYPE; break; case txAExprResult::STRING: resultType = XPathResult::STRING_TYPE; break; case txAExprResult::BOOLEAN: resultType = XPathResult::BOOLEAN_TYPE; break; case txAExprResult::NODESET: resultType = XPathResult::UNORDERED_NODE_ITERATOR_TYPE; break; case txAExprResult::RESULT_TREE_FRAGMENT: aRv.Throw(NS_ERROR_FAILURE); return nullptr; } } RefPtr<XPathResult> xpathResult = aInResult; if (!xpathResult) { xpathResult = new XPathResult(&aContextNode); } aRv = xpathResult->SetExprResult(exprResult, resultType, &aContextNode); return xpathResult.forget(); }
/** * Evaluates this Expr based on the given context node and processor state * @param context the context node for evaluation of this Expr * @param ps the ContextState containing the stack information needed * for evaluation * @return the result of the evaluation **/ nsresult PathExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult) { *aResult = nsnull; // We need to evaluate the first step with the current context since it // can depend on the context size and position. For example: // key('books', concat('book', position())) nsRefPtr<txAExprResult> res; nsresult rv = mItems[0].expr->evaluate(aContext, getter_AddRefs(res)); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(res->getResultType() == txAExprResult::NODESET, NS_ERROR_XSLT_NODESET_EXPECTED); nsRefPtr<txNodeSet> nodes = static_cast<txNodeSet*> (static_cast<txAExprResult*> (res)); if (nodes->isEmpty()) { res.swap(*aResult); return NS_OK; } res = nsnull; // To allow recycling // Evaluate remaining steps PRUint32 i, len = mItems.Length(); for (i = 1; i < len; ++i) { PathExprItem& pxi = mItems[i]; nsRefPtr<txNodeSet> tmpNodes; txNodeSetContext eContext(nodes, aContext); while (eContext.hasNext()) { eContext.next(); nsRefPtr<txNodeSet> resNodes; if (pxi.pathOp == DESCENDANT_OP) { rv = aContext->recycler()->getNodeSet(getter_AddRefs(resNodes)); NS_ENSURE_SUCCESS(rv, rv); rv = evalDescendants(pxi.expr, eContext.getContextNode(), &eContext, resNodes); NS_ENSURE_SUCCESS(rv, rv); } else { nsRefPtr<txAExprResult> res; rv = pxi.expr->evaluate(&eContext, getter_AddRefs(res)); NS_ENSURE_SUCCESS(rv, rv); if (res->getResultType() != txAExprResult::NODESET) { //XXX ErrorReport: report nonnodeset error return NS_ERROR_XSLT_NODESET_EXPECTED; } resNodes = static_cast<txNodeSet*> (static_cast<txAExprResult*> (res)); } if (tmpNodes) { if (!resNodes->isEmpty()) { nsRefPtr<txNodeSet> oldSet; oldSet.swap(tmpNodes); rv = aContext->recycler()-> getNonSharedNodeSet(oldSet, getter_AddRefs(tmpNodes)); NS_ENSURE_SUCCESS(rv, rv); oldSet.swap(resNodes); rv = aContext->recycler()-> getNonSharedNodeSet(oldSet, getter_AddRefs(resNodes)); NS_ENSURE_SUCCESS(rv, rv); tmpNodes->addAndTransfer(resNodes); } } else { tmpNodes = resNodes; } } nodes = tmpNodes; if (nodes->isEmpty()) { break; } } *aResult = nodes; NS_ADDREF(*aResult); return NS_OK; } //-- evaluate
NS_IMETHODIMP nsXPathExpression::EvaluateWithContext(nsIDOMNode *aContextNode, PRUint32 aContextPosition, PRUint32 aContextSize, PRUint16 aType, nsISupports *aInResult, nsISupports **aResult) { NS_ENSURE_ARG(aContextNode); if (aContextPosition > aContextSize) return NS_ERROR_FAILURE; if (!URIUtils::CanCallerAccess(aContextNode)) return NS_ERROR_DOM_SECURITY_ERR; nsresult rv; PRUint16 nodeType; rv = aContextNode->GetNodeType(&nodeType); NS_ENSURE_SUCCESS(rv, rv); if (nodeType == nsIDOMNode::TEXT_NODE || nodeType == nsIDOMNode::CDATA_SECTION_NODE) { nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(aContextNode); NS_ENSURE_TRUE(textNode, NS_ERROR_FAILURE); if (textNode) { PRUint32 textLength; textNode->GetLength(&textLength); if (textLength == 0) return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } // XXX Need to get logical XPath text node for CDATASection // and Text nodes. } else if (nodeType != nsIDOMNode::DOCUMENT_NODE && nodeType != nsIDOMNode::ELEMENT_NODE && nodeType != nsIDOMNode::ATTRIBUTE_NODE && nodeType != nsIDOMNode::COMMENT_NODE && nodeType != nsIDOMNode::PROCESSING_INSTRUCTION_NODE && nodeType != nsIDOMXPathNamespace::XPATH_NAMESPACE_NODE) { return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } NS_ENSURE_ARG(aResult); *aResult = nsnull; nsAutoPtr<txXPathNode> contextNode(txXPathNativeNode::createXPathNode(aContextNode)); if (!contextNode) { return NS_ERROR_OUT_OF_MEMORY; } EvalContextImpl eContext(*contextNode, aContextPosition, aContextSize, mRecycler); nsRefPtr<txAExprResult> exprResult; rv = mExpression->evaluate(&eContext, getter_AddRefs(exprResult)); NS_ENSURE_SUCCESS(rv, rv); PRUint16 resultType = aType; if (aType == nsIDOMXPathResult::ANY_TYPE) { short exprResultType = exprResult->getResultType(); switch (exprResultType) { case txAExprResult::NUMBER: resultType = nsIDOMXPathResult::NUMBER_TYPE; break; case txAExprResult::STRING: resultType = nsIDOMXPathResult::STRING_TYPE; break; case txAExprResult::BOOLEAN: resultType = nsIDOMXPathResult::BOOLEAN_TYPE; break; case txAExprResult::NODESET: resultType = nsIDOMXPathResult::UNORDERED_NODE_ITERATOR_TYPE; break; case txAExprResult::RESULT_TREE_FRAGMENT: NS_ERROR("Can't return a tree fragment!"); return NS_ERROR_FAILURE; } } // We need a result object and it must be our implementation. nsCOMPtr<nsIXPathResult> xpathResult = do_QueryInterface(aInResult); if (!xpathResult) { // Either no aInResult or not one of ours. xpathResult = new nsXPathResult(); NS_ENSURE_TRUE(xpathResult, NS_ERROR_OUT_OF_MEMORY); } rv = xpathResult->SetExprResult(exprResult, resultType); NS_ENSURE_SUCCESS(rv, rv); return CallQueryInterface(xpathResult, aResult); }