dom/xslt/xpath/txLocationStep.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial