Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /*
7 : * DocumentFunctionCall
8 : * A representation of the XSLT additional function: document()
9 : */
10 :
11 : #include "nsGkAtoms.h"
12 : #include "txIXPathContext.h"
13 : #include "txXSLTFunctions.h"
14 : #include "txExecutionState.h"
15 : #include "txURIUtils.h"
16 :
17 : /*
18 : * Creates a new DocumentFunctionCall.
19 : */
20 0 : DocumentFunctionCall::DocumentFunctionCall(const nsAString& aBaseURI)
21 0 : : mBaseURI(aBaseURI)
22 : {
23 0 : }
24 :
25 : static void
26 0 : retrieveNode(txExecutionState* aExecutionState, const nsAString& aUri,
27 : const nsAString& aBaseUri, txNodeSet* aNodeSet)
28 : {
29 0 : nsAutoString absUrl;
30 0 : URIUtils::resolveHref(aUri, aBaseUri, absUrl);
31 :
32 0 : int32_t hash = absUrl.RFindChar(char16_t('#'));
33 : uint32_t urlEnd, fragStart, fragEnd;
34 0 : if (hash == kNotFound) {
35 0 : urlEnd = absUrl.Length();
36 0 : fragStart = 0;
37 0 : fragEnd = 0;
38 : }
39 : else {
40 0 : urlEnd = hash;
41 0 : fragStart = hash + 1;
42 0 : fragEnd = absUrl.Length();
43 : }
44 :
45 0 : nsDependentSubstring docUrl(absUrl, 0, urlEnd);
46 0 : nsDependentSubstring frag(absUrl, fragStart, fragEnd);
47 :
48 0 : const txXPathNode* loadNode = aExecutionState->retrieveDocument(docUrl);
49 0 : if (loadNode) {
50 0 : if (frag.IsEmpty()) {
51 0 : aNodeSet->add(*loadNode);
52 : }
53 : else {
54 0 : txXPathTreeWalker walker(*loadNode);
55 0 : if (walker.moveToElementById(frag)) {
56 0 : aNodeSet->add(walker.getCurrentPosition());
57 : }
58 : }
59 : }
60 0 : }
61 :
62 : /*
63 : * Evaluates this Expr based on the given context node and processor state
64 : * NOTE: the implementation is incomplete since it does not make use of the
65 : * second argument (base URI)
66 : * @param context the context node for evaluation of this Expr
67 : * @return the result of the evaluation
68 : */
69 : nsresult
70 0 : DocumentFunctionCall::evaluate(txIEvalContext* aContext,
71 : txAExprResult** aResult)
72 : {
73 0 : *aResult = nullptr;
74 : txExecutionState* es =
75 0 : static_cast<txExecutionState*>(aContext->getPrivateContext());
76 :
77 0 : RefPtr<txNodeSet> nodeSet;
78 0 : nsresult rv = aContext->recycler()->getNodeSet(getter_AddRefs(nodeSet));
79 0 : NS_ENSURE_SUCCESS(rv, rv);
80 :
81 : // document(object, node-set?)
82 0 : if (!requireParams(1, 2, aContext)) {
83 0 : return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
84 : }
85 :
86 0 : RefPtr<txAExprResult> exprResult1;
87 0 : rv = mParams[0]->evaluate(aContext, getter_AddRefs(exprResult1));
88 0 : NS_ENSURE_SUCCESS(rv, rv);
89 :
90 0 : nsAutoString baseURI;
91 0 : bool baseURISet = false;
92 :
93 0 : if (mParams.Length() == 2) {
94 : // We have 2 arguments, get baseURI from the first node
95 : // in the resulting nodeset
96 0 : RefPtr<txNodeSet> nodeSet2;
97 0 : rv = evaluateToNodeSet(mParams[1],
98 0 : aContext, getter_AddRefs(nodeSet2));
99 0 : NS_ENSURE_SUCCESS(rv, rv);
100 :
101 : // Make this true, even if nodeSet2 is empty. For relative URLs,
102 : // we'll fail to load the document with an empty base URI, and for
103 : // absolute URLs, the base URI doesn't matter
104 0 : baseURISet = true;
105 :
106 0 : if (!nodeSet2->isEmpty()) {
107 0 : rv = txXPathNodeUtils::getBaseURI(nodeSet2->get(0), baseURI);
108 0 : NS_ENSURE_SUCCESS(rv, rv);
109 : }
110 : }
111 :
112 0 : if (exprResult1->getResultType() == txAExprResult::NODESET) {
113 : // The first argument is a NodeSet, iterate on its nodes
114 : txNodeSet* nodeSet1 = static_cast<txNodeSet*>
115 : (static_cast<txAExprResult*>
116 0 : (exprResult1));
117 : int32_t i;
118 0 : for (i = 0; i < nodeSet1->size(); ++i) {
119 0 : const txXPathNode& node = nodeSet1->get(i);
120 0 : nsAutoString uriStr;
121 0 : txXPathNodeUtils::appendNodeValue(node, uriStr);
122 0 : if (!baseURISet) {
123 : // if the second argument wasn't specified, use
124 : // the baseUri of node itself
125 0 : rv = txXPathNodeUtils::getBaseURI(node, baseURI);
126 0 : NS_ENSURE_SUCCESS(rv, rv);
127 : }
128 0 : retrieveNode(es, uriStr, baseURI, nodeSet);
129 : }
130 :
131 0 : NS_ADDREF(*aResult = nodeSet);
132 :
133 0 : return NS_OK;
134 : }
135 :
136 : // The first argument is not a NodeSet
137 0 : nsAutoString uriStr;
138 0 : exprResult1->stringValue(uriStr);
139 0 : const nsAString* base = baseURISet ? &baseURI : &mBaseURI;
140 0 : retrieveNode(es, uriStr, *base, nodeSet);
141 :
142 0 : NS_ADDREF(*aResult = nodeSet);
143 :
144 0 : return NS_OK;
145 : }
146 :
147 : Expr::ResultType
148 0 : DocumentFunctionCall::getReturnType()
149 : {
150 0 : return NODESET_RESULT;
151 : }
152 :
153 : bool
154 0 : DocumentFunctionCall::isSensitiveTo(ContextSensitivity aContext)
155 : {
156 0 : return (aContext & PRIVATE_CONTEXT) || argsSensitiveTo(aContext);
157 : }
158 :
159 : #ifdef TX_TO_STRING
160 : nsresult
161 0 : DocumentFunctionCall::getNameAtom(nsIAtom** aAtom)
162 : {
163 0 : *aAtom = nsGkAtoms::document;
164 0 : NS_ADDREF(*aAtom);
165 0 : return NS_OK;
166 : }
167 : #endif
|