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/. */
7 Implementation of an XPath LocationStep
11 #include "txIXPathContext.h"
12 #include "txNodeSet.h"
13 #include "txXPathTreeWalker.h"
15 //-----------------------------/
16 //- Virtual methods from Expr -/
17 //-----------------------------/
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
24 * @return the result of the evaluation
28 LocationStep::evaluate(txIEvalContext
* aContext
, txAExprResult
** aResult
)
30 NS_ASSERTION(aContext
, "internal error");
33 nsRefPtr
<txNodeSet
> nodes
;
34 nsresult rv
= aContext
->recycler()->getNodeSet(getter_AddRefs(nodes
));
35 NS_ENSURE_SUCCESS(rv
, rv
);
37 txXPathTreeWalker
walker(aContext
->getContextNode());
39 switch (mAxisIdentifier
) {
42 if (!walker
.moveToParent()) {
47 case ANCESTOR_OR_SELF_AXIS
:
52 if (mNodeTest
->matches(walker
.getCurrentPosition(), aContext
)) {
53 nodes
->append(walker
.getCurrentPosition());
55 } while (walker
.moveToParent());
61 if (!walker
.moveToFirstAttribute()) {
66 if (mNodeTest
->matches(walker
.getCurrentPosition(), aContext
)) {
67 nodes
->append(walker
.getCurrentPosition());
69 } while (walker
.moveToNextAttribute());
72 case DESCENDANT_OR_SELF_AXIS
:
74 if (mNodeTest
->matches(walker
.getCurrentPosition(), aContext
)) {
75 nodes
->append(walker
.getCurrentPosition());
81 fromDescendants(walker
.getCurrentPosition(), aContext
, nodes
);
86 if (txXPathNodeUtils::isAttribute(walker
.getCurrentPosition())) {
87 walker
.moveToParent();
88 fromDescendants(walker
.getCurrentPosition(), aContext
, nodes
);
91 while (!walker
.moveToNextSibling()) {
92 if (!walker
.moveToParent()) {
98 if (mNodeTest
->matches(walker
.getCurrentPosition(), aContext
)) {
99 nodes
->append(walker
.getCurrentPosition());
102 fromDescendants(walker
.getCurrentPosition(), aContext
, nodes
);
104 while (!walker
.moveToNextSibling()) {
105 if (!walker
.moveToParent()) {
113 case FOLLOWING_SIBLING_AXIS
:
115 while (walker
.moveToNextSibling()) {
116 if (mNodeTest
->matches(walker
.getCurrentPosition(), aContext
)) {
117 nodes
->append(walker
.getCurrentPosition());
122 case NAMESPACE_AXIS
: //-- not yet implemented
125 cout
<< "namespace axis not yet implemented"<<endl
;
130 if (walker
.moveToParent() &&
131 mNodeTest
->matches(walker
.getCurrentPosition(), aContext
)) {
132 nodes
->append(walker
.getCurrentPosition());
141 while (!walker
.moveToPreviousSibling()) {
142 if (!walker
.moveToParent()) {
148 fromDescendantsRev(walker
.getCurrentPosition(), aContext
, nodes
);
150 if (mNodeTest
->matches(walker
.getCurrentPosition(), aContext
)) {
151 nodes
->append(walker
.getCurrentPosition());
154 while (!walker
.moveToPreviousSibling()) {
155 if (!walker
.moveToParent()) {
163 case PRECEDING_SIBLING_AXIS
:
167 while (walker
.moveToPreviousSibling()) {
168 if (mNodeTest
->matches(walker
.getCurrentPosition(), aContext
)) {
169 nodes
->append(walker
.getCurrentPosition());
176 if (mNodeTest
->matches(walker
.getCurrentPosition(), aContext
)) {
177 nodes
->append(walker
.getCurrentPosition());
181 default: // Children Axis
183 if (!walker
.moveToFirstChild()) {
188 if (mNodeTest
->matches(walker
.getCurrentPosition(), aContext
)) {
189 nodes
->append(walker
.getCurrentPosition());
191 } while (walker
.moveToNextSibling());
198 rv
= evaluatePredicates(nodes
, aContext
);
199 NS_ENSURE_SUCCESS(rv
, rv
);
202 nodes
->unsetReverse();
204 NS_ADDREF(*aResult
= nodes
);
209 void LocationStep::fromDescendants(const txXPathNode
& aNode
,
210 txIMatchContext
* aCs
,
213 txXPathTreeWalker
walker(aNode
);
214 if (!walker
.moveToFirstChild()) {
219 const txXPathNode
& child
= walker
.getCurrentPosition();
220 if (mNodeTest
->matches(child
, aCs
)) {
221 aNodes
->append(child
);
223 fromDescendants(child
, aCs
, aNodes
);
224 } while (walker
.moveToNextSibling());
227 void LocationStep::fromDescendantsRev(const txXPathNode
& aNode
,
228 txIMatchContext
* aCs
,
231 txXPathTreeWalker
walker(aNode
);
232 if (!walker
.moveToLastChild()) {
237 const txXPathNode
& child
= walker
.getCurrentPosition();
238 fromDescendantsRev(child
, aCs
, aNodes
);
240 if (mNodeTest
->matches(child
, aCs
)) {
241 aNodes
->append(child
);
244 } while (walker
.moveToPreviousSibling());
248 LocationStep::getType()
250 return LOCATIONSTEP_EXPR
;
254 TX_IMPL_EXPR_STUBS_BASE(LocationStep
, NODESET_RESULT
)
257 LocationStep::getSubExprAt(uint32_t aPos
)
259 return PredicateList::getSubExprAt(aPos
);
263 LocationStep::setSubExprAt(uint32_t aPos
, Expr
* aExpr
)
265 PredicateList::setSubExprAt(aPos
, aExpr
);
269 LocationStep::isSensitiveTo(ContextSensitivity aContext
)
271 return (aContext
& NODE_CONTEXT
) ||
272 mNodeTest
->isSensitiveTo(aContext
) ||
273 PredicateList::isSensitiveTo(aContext
);
278 LocationStep::toString(nsAString
& str
)
280 switch (mAxisIdentifier
) {
282 str
.AppendLiteral("ancestor::");
284 case ANCESTOR_OR_SELF_AXIS
:
285 str
.AppendLiteral("ancestor-or-self::");
288 str
.Append(char16_t('@'));
290 case DESCENDANT_AXIS
:
291 str
.AppendLiteral("descendant::");
293 case DESCENDANT_OR_SELF_AXIS
:
294 str
.AppendLiteral("descendant-or-self::");
296 case FOLLOWING_AXIS
:
297 str
.AppendLiteral("following::");
299 case FOLLOWING_SIBLING_AXIS
:
300 str
.AppendLiteral("following-sibling::");
303 str
.AppendLiteral("namespace::");
306 str
.AppendLiteral("parent::");
308 case PRECEDING_AXIS
:
309 str
.AppendLiteral("preceding::");
311 case PRECEDING_SIBLING_AXIS
:
312 str
.AppendLiteral("preceding-sibling::");
315 str
.AppendLiteral("self::");
320 NS_ASSERTION(mNodeTest
, "mNodeTest is null, that's verboten");
321 mNodeTest
->toString(str
);
323 PredicateList::toString(str
);