1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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
27 nsresult
LocationStep::evaluate(txIEvalContext
* aContext
,
28 txAExprResult
** aResult
) {
29 NS_ASSERTION(aContext
, "internal error");
32 RefPtr
<txNodeSet
> nodes
;
33 nsresult rv
= aContext
->recycler()->getNodeSet(getter_AddRefs(nodes
));
34 NS_ENSURE_SUCCESS(rv
, rv
);
36 txXPathTreeWalker
walker(aContext
->getContextNode());
38 switch (mAxisIdentifier
) {
40 if (!walker
.moveToParent()) {
45 case ANCESTOR_OR_SELF_AXIS
: {
49 rv
= appendIfMatching(walker
, aContext
, nodes
);
50 NS_ENSURE_SUCCESS(rv
, rv
);
51 } while (walker
.moveToParent());
55 case ATTRIBUTE_AXIS
: {
56 if (!walker
.moveToFirstAttribute()) {
61 rv
= appendIfMatching(walker
, aContext
, nodes
);
62 NS_ENSURE_SUCCESS(rv
, rv
);
63 } while (walker
.moveToNextAttribute());
66 case DESCENDANT_OR_SELF_AXIS
: {
67 rv
= appendIfMatching(walker
, aContext
, nodes
);
68 NS_ENSURE_SUCCESS(rv
, rv
);
71 case DESCENDANT_AXIS
: {
72 rv
= appendMatchingDescendants(walker
, aContext
, nodes
);
73 NS_ENSURE_SUCCESS(rv
, rv
);
76 case FOLLOWING_AXIS
: {
77 if (txXPathNodeUtils::isAttribute(walker
.getCurrentPosition())) {
78 walker
.moveToParent();
79 rv
= appendMatchingDescendants(walker
, aContext
, nodes
);
80 NS_ENSURE_SUCCESS(rv
, rv
);
83 while (!walker
.moveToNextSibling()) {
84 if (!walker
.moveToParent()) {
90 rv
= appendIfMatching(walker
, aContext
, nodes
);
91 NS_ENSURE_SUCCESS(rv
, rv
);
93 rv
= appendMatchingDescendants(walker
, aContext
, nodes
);
94 NS_ENSURE_SUCCESS(rv
, rv
);
96 while (!walker
.moveToNextSibling()) {
97 if (!walker
.moveToParent()) {
105 case FOLLOWING_SIBLING_AXIS
: {
106 while (walker
.moveToNextSibling()) {
107 rv
= appendIfMatching(walker
, aContext
, nodes
);
108 NS_ENSURE_SUCCESS(rv
, rv
);
112 case NAMESPACE_AXIS
: //-- not yet implemented
115 cout
<< "namespace axis not yet implemented"<<endl
;
119 if (walker
.moveToParent()) {
120 rv
= appendIfMatching(walker
, aContext
, nodes
);
121 NS_ENSURE_SUCCESS(rv
, rv
);
125 case PRECEDING_AXIS
: {
129 while (!walker
.moveToPreviousSibling()) {
130 if (!walker
.moveToParent()) {
136 rv
= appendMatchingDescendantsRev(walker
, aContext
, nodes
);
137 NS_ENSURE_SUCCESS(rv
, rv
);
139 rv
= appendIfMatching(walker
, aContext
, nodes
);
140 NS_ENSURE_SUCCESS(rv
, rv
);
142 while (!walker
.moveToPreviousSibling()) {
143 if (!walker
.moveToParent()) {
151 case PRECEDING_SIBLING_AXIS
: {
154 while (walker
.moveToPreviousSibling()) {
155 rv
= appendIfMatching(walker
, aContext
, nodes
);
156 NS_ENSURE_SUCCESS(rv
, rv
);
161 rv
= appendIfMatching(walker
, aContext
, nodes
);
162 NS_ENSURE_SUCCESS(rv
, rv
);
165 default: // Children Axis
167 if (!walker
.moveToFirstChild()) {
172 rv
= appendIfMatching(walker
, aContext
, nodes
);
173 NS_ENSURE_SUCCESS(rv
, rv
);
174 } while (walker
.moveToNextSibling());
181 rv
= evaluatePredicates(nodes
, aContext
);
182 NS_ENSURE_SUCCESS(rv
, rv
);
185 nodes
->unsetReverse();
187 NS_ADDREF(*aResult
= nodes
);
192 nsresult
LocationStep::appendIfMatching(const txXPathTreeWalker
& aWalker
,
193 txIMatchContext
* aContext
,
196 const txXPathNode
& child
= aWalker
.getCurrentPosition();
197 nsresult rv
= mNodeTest
->matches(child
, aContext
, matched
);
198 NS_ENSURE_SUCCESS(rv
, rv
);
201 aNodes
->append(child
);
206 nsresult
LocationStep::appendMatchingDescendants(
207 const txXPathTreeWalker
& aWalker
, txIMatchContext
* aContext
,
209 txXPathTreeWalker
walker(aWalker
);
210 if (!walker
.moveToFirstChild()) {
215 nsresult rv
= appendIfMatching(walker
, aContext
, aNodes
);
216 NS_ENSURE_SUCCESS(rv
, rv
);
218 rv
= appendMatchingDescendants(walker
, aContext
, aNodes
);
219 NS_ENSURE_SUCCESS(rv
, rv
);
220 } while (walker
.moveToNextSibling());
225 nsresult
LocationStep::appendMatchingDescendantsRev(
226 const txXPathTreeWalker
& aWalker
, txIMatchContext
* aContext
,
228 txXPathTreeWalker
walker(aWalker
);
229 if (!walker
.moveToLastChild()) {
234 nsresult rv
= appendMatchingDescendantsRev(walker
, aContext
, aNodes
);
235 NS_ENSURE_SUCCESS(rv
, rv
);
237 rv
= appendIfMatching(walker
, aContext
, aNodes
);
238 NS_ENSURE_SUCCESS(rv
, rv
);
239 } while (walker
.moveToPreviousSibling());
244 Expr::ExprType
LocationStep::getType() { return LOCATIONSTEP_EXPR
; }
246 TX_IMPL_EXPR_STUBS_BASE(LocationStep
, NODESET_RESULT
)
248 Expr
* LocationStep::getSubExprAt(uint32_t aPos
) {
249 return PredicateList::getSubExprAt(aPos
);
252 void LocationStep::setSubExprAt(uint32_t aPos
, Expr
* aExpr
) {
253 PredicateList::setSubExprAt(aPos
, aExpr
);
256 bool LocationStep::isSensitiveTo(ContextSensitivity aContext
) {
257 return (aContext
& NODE_CONTEXT
) || mNodeTest
->isSensitiveTo(aContext
) ||
258 PredicateList::isSensitiveTo(aContext
);
262 void LocationStep::toString(nsAString
& str
) {
263 switch (mAxisIdentifier
) {
265 str
.AppendLiteral("ancestor::");
267 case ANCESTOR_OR_SELF_AXIS
:
268 str
.AppendLiteral("ancestor-or-self::");
271 str
.Append(char16_t('@'));
273 case DESCENDANT_AXIS
:
274 str
.AppendLiteral("descendant::");
276 case DESCENDANT_OR_SELF_AXIS
:
277 str
.AppendLiteral("descendant-or-self::");
280 str
.AppendLiteral("following::");
282 case FOLLOWING_SIBLING_AXIS
:
283 str
.AppendLiteral("following-sibling::");
286 str
.AppendLiteral("namespace::");
289 str
.AppendLiteral("parent::");
292 str
.AppendLiteral("preceding::");
294 case PRECEDING_SIBLING_AXIS
:
295 str
.AppendLiteral("preceding-sibling::");
298 str
.AppendLiteral("self::");
303 NS_ASSERTION(mNodeTest
, "mNodeTest is null, that's verboten");
304 mNodeTest
->toString(str
);
306 PredicateList::toString(str
);