Back to index

lightning-sunbird  0.9+nobinonly
LocationStep.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is TransforMiiX XSLT processor code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * The MITRE Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Keith Visco <kvisco@ziplink.net> (Original Author)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 /*
00040   Implementation of an XPath LocationStep
00041 */
00042 
00043 #include "Expr.h"
00044 #include "txIXPathContext.h"
00045 #include "txNodeSet.h"
00046 
00047   //-----------------------------/
00048  //- Virtual methods from Expr -/
00049 //-----------------------------/
00050 
00059 nsresult
00060 LocationStep::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
00061 {
00062     NS_ASSERTION(aContext, "internal error");
00063     *aResult = nsnull;
00064 
00065     nsRefPtr<txNodeSet> nodes;
00066     nsresult rv = aContext->recycler()->getNodeSet(getter_AddRefs(nodes));
00067     NS_ENSURE_SUCCESS(rv, rv);
00068 
00069     txXPathTreeWalker walker(aContext->getContextNode());
00070 
00071     switch (mAxisIdentifier) {
00072         case ANCESTOR_AXIS:
00073         {
00074             if (!walker.moveToParent()) {
00075                 break;
00076             }
00077             // do not break here
00078         }
00079         case ANCESTOR_OR_SELF_AXIS:
00080         {
00081             nodes->setReverse();
00082 
00083             do {
00084                 if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
00085                     nodes->append(walker.getCurrentPosition());
00086                 }
00087             } while (walker.moveToParent());
00088 
00089             break;
00090         }
00091         case ATTRIBUTE_AXIS:
00092         {
00093             if (!walker.moveToFirstAttribute()) {
00094                 break;
00095             }
00096 
00097             do {
00098                 if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
00099                     nodes->append(walker.getCurrentPosition());
00100                 }
00101             } while (walker.moveToNextAttribute());
00102             break;
00103         }
00104         case DESCENDANT_OR_SELF_AXIS:
00105         {
00106             if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
00107                 nodes->append(walker.getCurrentPosition());
00108             }
00109             // do not break here
00110         }
00111         case DESCENDANT_AXIS:
00112         {
00113             fromDescendants(walker.getCurrentPosition(), aContext, nodes);
00114             break;
00115         }
00116         case FOLLOWING_AXIS:
00117         {
00118             if (txXPathNodeUtils::isAttribute(walker.getCurrentPosition())) {
00119                 walker.moveToParent();
00120                 fromDescendants(walker.getCurrentPosition(), aContext, nodes);
00121             }
00122             PRBool cont = PR_TRUE;
00123             while (!walker.moveToNextSibling()) {
00124                 if (!walker.moveToParent()) {
00125                     cont = PR_FALSE;
00126                     break;
00127                 }
00128             }
00129             while (cont) {
00130                 if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
00131                     nodes->append(walker.getCurrentPosition());
00132                 }
00133 
00134                 fromDescendants(walker.getCurrentPosition(), aContext, nodes);
00135 
00136                 while (!walker.moveToNextSibling()) {
00137                     if (!walker.moveToParent()) {
00138                         cont = PR_FALSE;
00139                         break;
00140                     }
00141                 }
00142             }
00143             break;
00144         }
00145         case FOLLOWING_SIBLING_AXIS:
00146         {
00147             while (walker.moveToNextSibling()) {
00148                 if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
00149                     nodes->append(walker.getCurrentPosition());
00150                 }
00151             }
00152             break;
00153         }
00154         case NAMESPACE_AXIS: //-- not yet implemented
00155 #if 0
00156             // XXX DEBUG OUTPUT
00157             cout << "namespace axis not yet implemented"<<endl;
00158 #endif
00159             break;
00160         case PARENT_AXIS :
00161         {
00162             if (walker.moveToParent() &&
00163                 mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
00164                 nodes->append(walker.getCurrentPosition());
00165             }
00166             break;
00167         }
00168         case PRECEDING_AXIS:
00169         {
00170             nodes->setReverse();
00171 
00172             PRBool cont = PR_TRUE;
00173             while (!walker.moveToPreviousSibling()) {
00174                 if (!walker.moveToParent()) {
00175                     cont = PR_FALSE;
00176                     break;
00177                 }
00178             }
00179             while (cont) {
00180                 fromDescendantsRev(walker.getCurrentPosition(), aContext, nodes);
00181 
00182                 if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
00183                     nodes->append(walker.getCurrentPosition());
00184                 }
00185 
00186                 while (!walker.moveToPreviousSibling()) {
00187                     if (!walker.moveToParent()) {
00188                         cont = PR_FALSE;
00189                         break;
00190                     }
00191                 }
00192             }
00193             break;
00194         }
00195         case PRECEDING_SIBLING_AXIS:
00196         {
00197             nodes->setReverse();
00198 
00199             while (walker.moveToPreviousSibling()) {
00200                 if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
00201                     nodes->append(walker.getCurrentPosition());
00202                 }
00203             }
00204             break;
00205         }
00206         case SELF_AXIS:
00207         {
00208             if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
00209                 nodes->append(walker.getCurrentPosition());
00210             }
00211             break;
00212         }
00213         default: // Children Axis
00214         {
00215             if (!walker.moveToFirstChild()) {
00216                 break;
00217             }
00218 
00219             do {
00220                 if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
00221                     nodes->append(walker.getCurrentPosition());
00222                 }
00223             } while (walker.moveToNextSibling());
00224             break;
00225         }
00226     }
00227 
00228     // Apply predicates
00229     if (!isEmpty()) {
00230         rv = evaluatePredicates(nodes, aContext);
00231         NS_ENSURE_SUCCESS(rv, rv);
00232     }
00233 
00234     nodes->unsetReverse();
00235 
00236     NS_ADDREF(*aResult = nodes);
00237 
00238     return NS_OK;
00239 }
00240 
00241 void LocationStep::fromDescendants(const txXPathNode& aNode,
00242                                    txIMatchContext* aCs,
00243                                    txNodeSet* aNodes)
00244 {
00245     txXPathTreeWalker walker(aNode);
00246     if (!walker.moveToFirstChild()) {
00247         return;
00248     }
00249 
00250     do {
00251         const txXPathNode& child = walker.getCurrentPosition();
00252         if (mNodeTest->matches(child, aCs)) {
00253             aNodes->append(child);
00254         }
00255         fromDescendants(child, aCs, aNodes);
00256     } while (walker.moveToNextSibling());
00257 }
00258 
00259 void LocationStep::fromDescendantsRev(const txXPathNode& aNode,
00260                                       txIMatchContext* aCs,
00261                                       txNodeSet* aNodes)
00262 {
00263     txXPathTreeWalker walker(aNode);
00264     if (!walker.moveToLastChild()) {
00265         return;
00266     }
00267 
00268     do {
00269         const txXPathNode& child = walker.getCurrentPosition();
00270         fromDescendantsRev(child, aCs, aNodes);
00271 
00272         if (mNodeTest->matches(child, aCs)) {
00273             aNodes->append(child);
00274         }
00275 
00276     } while (walker.moveToPreviousSibling());
00277 }
00278 
00279 #ifdef TX_TO_STRING
00280 void
00281 LocationStep::toString(nsAString& str)
00282 {
00283     switch (mAxisIdentifier) {
00284         case ANCESTOR_AXIS :
00285             str.AppendLiteral("ancestor::");
00286             break;
00287         case ANCESTOR_OR_SELF_AXIS :
00288             str.AppendLiteral("ancestor-or-self::");
00289             break;
00290         case ATTRIBUTE_AXIS:
00291             str.Append(PRUnichar('@'));
00292             break;
00293         case DESCENDANT_AXIS:
00294             str.AppendLiteral("descendant::");
00295             break;
00296         case DESCENDANT_OR_SELF_AXIS:
00297             str.AppendLiteral("descendant-or-self::");
00298             break;
00299         case FOLLOWING_AXIS :
00300             str.AppendLiteral("following::");
00301             break;
00302         case FOLLOWING_SIBLING_AXIS:
00303             str.AppendLiteral("following-sibling::");
00304             break;
00305         case NAMESPACE_AXIS:
00306             str.AppendLiteral("namespace::");
00307             break;
00308         case PARENT_AXIS :
00309             str.AppendLiteral("parent::");
00310             break;
00311         case PRECEDING_AXIS :
00312             str.AppendLiteral("preceding::");
00313             break;
00314         case PRECEDING_SIBLING_AXIS :
00315             str.AppendLiteral("preceding-sibling::");
00316             break;
00317         case SELF_AXIS :
00318             str.AppendLiteral("self::");
00319             break;
00320         default:
00321             break;
00322     }
00323     NS_ASSERTION(mNodeTest, "mNodeTest is null, that's verboten");
00324     mNodeTest->toString(str);
00325 
00326     PredicateList::toString(str);
00327 }
00328 #endif