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