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 : Implementation of an XPath LocationStep
8 : */
9 :
10 : #include "txExpr.h"
11 : #include "txIXPathContext.h"
12 : #include "txNodeSet.h"
13 : #include "txXPathTreeWalker.h"
14 :
15 : //-----------------------------/
16 : //- Virtual methods from Expr -/
17 : //-----------------------------/
18 :
19 : /**
20 : * Evaluates this Expr based on the given context node and processor state
21 : * @param context the context node for evaluation of this Expr
22 : * @param ps the ProcessorState containing the stack information needed
23 : * for evaluation
24 : * @return the result of the evaluation
25 : * @see Expr
26 : **/
27 : nsresult
28 0 : LocationStep::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
29 : {
30 0 : NS_ASSERTION(aContext, "internal error");
31 0 : *aResult = nullptr;
32 :
33 0 : RefPtr<txNodeSet> nodes;
34 0 : nsresult rv = aContext->recycler()->getNodeSet(getter_AddRefs(nodes));
35 0 : NS_ENSURE_SUCCESS(rv, rv);
36 :
37 0 : txXPathTreeWalker walker(aContext->getContextNode());
38 :
39 0 : switch (mAxisIdentifier) {
40 : case ANCESTOR_AXIS:
41 : {
42 0 : if (!walker.moveToParent()) {
43 0 : break;
44 : }
45 : MOZ_FALLTHROUGH;
46 : }
47 : case ANCESTOR_OR_SELF_AXIS:
48 : {
49 0 : nodes->setReverse();
50 :
51 0 : do {
52 0 : rv = appendIfMatching(walker, aContext, nodes);
53 0 : NS_ENSURE_SUCCESS(rv, rv);
54 : } while (walker.moveToParent());
55 :
56 0 : break;
57 : }
58 : case ATTRIBUTE_AXIS:
59 : {
60 0 : if (!walker.moveToFirstAttribute()) {
61 0 : break;
62 : }
63 :
64 0 : do {
65 0 : rv = appendIfMatching(walker, aContext, nodes);
66 0 : NS_ENSURE_SUCCESS(rv, rv);
67 : } while (walker.moveToNextAttribute());
68 0 : break;
69 : }
70 : case DESCENDANT_OR_SELF_AXIS:
71 : {
72 0 : rv = appendIfMatching(walker, aContext, nodes);
73 0 : NS_ENSURE_SUCCESS(rv, rv);
74 : MOZ_FALLTHROUGH;
75 : }
76 : case DESCENDANT_AXIS:
77 : {
78 0 : rv = appendMatchingDescendants(walker, aContext, nodes);
79 0 : NS_ENSURE_SUCCESS(rv, rv);
80 0 : break;
81 : }
82 : case FOLLOWING_AXIS:
83 : {
84 0 : if (txXPathNodeUtils::isAttribute(walker.getCurrentPosition())) {
85 0 : walker.moveToParent();
86 0 : rv = appendMatchingDescendants(walker, aContext, nodes);
87 0 : NS_ENSURE_SUCCESS(rv, rv);
88 : }
89 0 : bool cont = true;
90 0 : while (!walker.moveToNextSibling()) {
91 0 : if (!walker.moveToParent()) {
92 0 : cont = false;
93 0 : break;
94 : }
95 : }
96 0 : while (cont) {
97 0 : rv = appendIfMatching(walker, aContext, nodes);
98 0 : NS_ENSURE_SUCCESS(rv, rv);
99 :
100 0 : rv = appendMatchingDescendants(walker, aContext, nodes);
101 0 : NS_ENSURE_SUCCESS(rv, rv);
102 :
103 0 : while (!walker.moveToNextSibling()) {
104 0 : if (!walker.moveToParent()) {
105 0 : cont = false;
106 0 : break;
107 : }
108 : }
109 : }
110 0 : break;
111 : }
112 : case FOLLOWING_SIBLING_AXIS:
113 : {
114 0 : while (walker.moveToNextSibling()) {
115 0 : rv = appendIfMatching(walker, aContext, nodes);
116 0 : NS_ENSURE_SUCCESS(rv, rv);
117 : }
118 0 : break;
119 : }
120 : case NAMESPACE_AXIS: //-- not yet implemented
121 : #if 0
122 : // XXX DEBUG OUTPUT
123 : cout << "namespace axis not yet implemented"<<endl;
124 : #endif
125 0 : break;
126 : case PARENT_AXIS :
127 : {
128 0 : if (walker.moveToParent()) {
129 0 : rv = appendIfMatching(walker, aContext, nodes);
130 0 : NS_ENSURE_SUCCESS(rv, rv);
131 : }
132 0 : break;
133 : }
134 : case PRECEDING_AXIS:
135 : {
136 0 : nodes->setReverse();
137 :
138 0 : bool cont = true;
139 0 : while (!walker.moveToPreviousSibling()) {
140 0 : if (!walker.moveToParent()) {
141 0 : cont = false;
142 0 : break;
143 : }
144 : }
145 0 : while (cont) {
146 0 : rv = appendMatchingDescendantsRev(walker, aContext, nodes);
147 0 : NS_ENSURE_SUCCESS(rv, rv);
148 :
149 0 : rv = appendIfMatching(walker, aContext, nodes);
150 0 : NS_ENSURE_SUCCESS(rv, rv);
151 :
152 0 : while (!walker.moveToPreviousSibling()) {
153 0 : if (!walker.moveToParent()) {
154 0 : cont = false;
155 0 : break;
156 : }
157 : }
158 : }
159 0 : break;
160 : }
161 : case PRECEDING_SIBLING_AXIS:
162 : {
163 0 : nodes->setReverse();
164 :
165 0 : while (walker.moveToPreviousSibling()) {
166 0 : rv = appendIfMatching(walker, aContext, nodes);
167 0 : NS_ENSURE_SUCCESS(rv, rv);
168 : }
169 0 : break;
170 : }
171 : case SELF_AXIS:
172 : {
173 0 : rv = appendIfMatching(walker, aContext, nodes);
174 0 : NS_ENSURE_SUCCESS(rv, rv);
175 0 : break;
176 : }
177 : default: // Children Axis
178 : {
179 0 : if (!walker.moveToFirstChild()) {
180 0 : break;
181 : }
182 :
183 0 : do {
184 0 : rv = appendIfMatching(walker, aContext, nodes);
185 0 : NS_ENSURE_SUCCESS(rv, rv);
186 : } while (walker.moveToNextSibling());
187 0 : break;
188 : }
189 : }
190 :
191 : // Apply predicates
192 0 : if (!isEmpty()) {
193 0 : rv = evaluatePredicates(nodes, aContext);
194 0 : NS_ENSURE_SUCCESS(rv, rv);
195 : }
196 :
197 0 : nodes->unsetReverse();
198 :
199 0 : NS_ADDREF(*aResult = nodes);
200 :
201 0 : return NS_OK;
202 : }
203 :
204 : nsresult
205 0 : LocationStep::appendIfMatching(const txXPathTreeWalker& aWalker,
206 : txIMatchContext* aContext,
207 : txNodeSet* aNodes)
208 : {
209 : bool matched;
210 0 : const txXPathNode& child = aWalker.getCurrentPosition();
211 0 : nsresult rv = mNodeTest->matches(child, aContext, matched);
212 0 : NS_ENSURE_SUCCESS(rv, rv);
213 :
214 0 : if (matched) {
215 0 : aNodes->append(child);
216 : }
217 0 : return NS_OK;
218 : }
219 :
220 : nsresult
221 0 : LocationStep::appendMatchingDescendants(const txXPathTreeWalker& aWalker,
222 : txIMatchContext* aContext,
223 : txNodeSet* aNodes)
224 : {
225 0 : txXPathTreeWalker walker(aWalker);
226 0 : if (!walker.moveToFirstChild()) {
227 0 : return NS_OK;
228 : }
229 :
230 0 : do {
231 0 : nsresult rv = appendIfMatching(walker, aContext, aNodes);
232 0 : NS_ENSURE_SUCCESS(rv, rv);
233 :
234 0 : rv = appendMatchingDescendants(walker, aContext, aNodes);
235 0 : NS_ENSURE_SUCCESS(rv, rv);
236 : } while (walker.moveToNextSibling());
237 :
238 0 : return NS_OK;
239 : }
240 :
241 : nsresult
242 0 : LocationStep::appendMatchingDescendantsRev(const txXPathTreeWalker& aWalker,
243 : txIMatchContext* aContext,
244 : txNodeSet* aNodes)
245 : {
246 0 : txXPathTreeWalker walker(aWalker);
247 0 : if (!walker.moveToLastChild()) {
248 0 : return NS_OK;
249 : }
250 :
251 0 : do {
252 0 : nsresult rv = appendMatchingDescendantsRev(walker, aContext, aNodes);
253 0 : NS_ENSURE_SUCCESS(rv, rv);
254 :
255 0 : rv = appendIfMatching(walker, aContext, aNodes);
256 0 : NS_ENSURE_SUCCESS(rv, rv);
257 : } while (walker.moveToPreviousSibling());
258 :
259 0 : return NS_OK;
260 : }
261 :
262 : Expr::ExprType
263 0 : LocationStep::getType()
264 : {
265 0 : return LOCATIONSTEP_EXPR;
266 : }
267 :
268 :
269 0 : TX_IMPL_EXPR_STUBS_BASE(LocationStep, NODESET_RESULT)
270 :
271 : Expr*
272 0 : LocationStep::getSubExprAt(uint32_t aPos)
273 : {
274 0 : return PredicateList::getSubExprAt(aPos);
275 : }
276 :
277 : void
278 0 : LocationStep::setSubExprAt(uint32_t aPos, Expr* aExpr)
279 : {
280 0 : PredicateList::setSubExprAt(aPos, aExpr);
281 0 : }
282 :
283 : bool
284 0 : LocationStep::isSensitiveTo(ContextSensitivity aContext)
285 : {
286 0 : return (aContext & NODE_CONTEXT) ||
287 0 : mNodeTest->isSensitiveTo(aContext) ||
288 0 : PredicateList::isSensitiveTo(aContext);
289 : }
290 :
291 : #ifdef TX_TO_STRING
292 : void
293 0 : LocationStep::toString(nsAString& str)
294 : {
295 0 : switch (mAxisIdentifier) {
296 : case ANCESTOR_AXIS :
297 0 : str.AppendLiteral("ancestor::");
298 0 : break;
299 : case ANCESTOR_OR_SELF_AXIS :
300 0 : str.AppendLiteral("ancestor-or-self::");
301 0 : break;
302 : case ATTRIBUTE_AXIS:
303 0 : str.Append(char16_t('@'));
304 0 : break;
305 : case DESCENDANT_AXIS:
306 0 : str.AppendLiteral("descendant::");
307 0 : break;
308 : case DESCENDANT_OR_SELF_AXIS:
309 0 : str.AppendLiteral("descendant-or-self::");
310 0 : break;
311 : case FOLLOWING_AXIS :
312 0 : str.AppendLiteral("following::");
313 0 : break;
314 : case FOLLOWING_SIBLING_AXIS:
315 0 : str.AppendLiteral("following-sibling::");
316 0 : break;
317 : case NAMESPACE_AXIS:
318 0 : str.AppendLiteral("namespace::");
319 0 : break;
320 : case PARENT_AXIS :
321 0 : str.AppendLiteral("parent::");
322 0 : break;
323 : case PRECEDING_AXIS :
324 0 : str.AppendLiteral("preceding::");
325 0 : break;
326 : case PRECEDING_SIBLING_AXIS :
327 0 : str.AppendLiteral("preceding-sibling::");
328 0 : break;
329 : case SELF_AXIS :
330 0 : str.AppendLiteral("self::");
331 0 : break;
332 : default:
333 0 : break;
334 : }
335 0 : NS_ASSERTION(mNodeTest, "mNodeTest is null, that's verboten");
336 0 : mNodeTest->toString(str);
337 :
338 0 : PredicateList::toString(str);
339 0 : }
340 : #endif
|