Home | History | Annotate | Download | only in axes
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one
      3  * or more contributor license agreements. See the NOTICE file
      4  * distributed with this work for additional information
      5  * regarding copyright ownership. The ASF licenses this file
      6  * to you under the Apache License, Version 2.0 (the  "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  */
     18 /*
     19  * $Id: MatchPatternIterator.java 469314 2006-10-30 23:31:59Z minchau $
     20  */
     21 package org.apache.xpath.axes;
     22 
     23 import org.apache.xml.dtm.Axis;
     24 import org.apache.xml.dtm.DTM;
     25 import org.apache.xml.dtm.DTMAxisTraverser;
     26 import org.apache.xml.dtm.DTMIterator;
     27 import org.apache.xpath.XPathContext;
     28 import org.apache.xpath.compiler.Compiler;
     29 import org.apache.xpath.compiler.OpMap;
     30 import org.apache.xpath.objects.XObject;
     31 import org.apache.xpath.patterns.NodeTest;
     32 import org.apache.xpath.patterns.StepPattern;
     33 
     34 /**
     35  * This class treats a
     36  * <a href="http://www.w3.org/TR/xpath#location-paths">LocationPath</a> as a
     37  * filtered iteration over the tree, evaluating each node in a super axis
     38  * traversal against the LocationPath interpreted as a match pattern.  This
     39  * class is useful to find nodes in document order that are complex paths
     40  * whose steps probably criss-cross each other.
     41  */
     42 public class MatchPatternIterator extends LocPathIterator
     43 {
     44     static final long serialVersionUID = -5201153767396296474L;
     45 
     46   /** This is the select pattern, translated into a match pattern. */
     47   protected StepPattern m_pattern;
     48 
     49   /** The traversal axis from where the nodes will be filtered. */
     50   protected int m_superAxis = -1;
     51 
     52   /** The DTM inner traversal class, that corresponds to the super axis. */
     53   protected DTMAxisTraverser m_traverser;
     54 
     55   /** DEBUG flag for diagnostic dumps. */
     56   private static final boolean DEBUG = false;
     57 
     58 //  protected int m_nsElemBase = DTM.NULL;
     59 
     60   /**
     61    * Create a LocPathIterator object, including creation
     62    * of step walkers from the opcode list, and call back
     63    * into the Compiler to create predicate expressions.
     64    *
     65    * @param compiler The Compiler which is creating
     66    * this expression.
     67    * @param opPos The position of this iterator in the
     68    * opcode list from the compiler.
     69    * @param analysis Analysis bits that give general information about the
     70    * LocationPath.
     71    *
     72    * @throws javax.xml.transform.TransformerException
     73    */
     74   MatchPatternIterator(Compiler compiler, int opPos, int analysis)
     75           throws javax.xml.transform.TransformerException
     76   {
     77 
     78     super(compiler, opPos, analysis, false);
     79 
     80     int firstStepPos = OpMap.getFirstChildPos(opPos);
     81 
     82     m_pattern = WalkerFactory.loadSteps(this, compiler, firstStepPos, 0);
     83 
     84     boolean fromRoot = false;
     85     boolean walkBack = false;
     86     boolean walkDescendants = false;
     87     boolean walkAttributes = false;
     88 
     89     if (0 != (analysis & (WalkerFactory.BIT_ROOT |
     90                           WalkerFactory.BIT_ANY_DESCENDANT_FROM_ROOT)))
     91       fromRoot = true;
     92 
     93     if (0 != (analysis
     94               & (WalkerFactory.BIT_ANCESTOR
     95                  | WalkerFactory.BIT_ANCESTOR_OR_SELF
     96                  | WalkerFactory.BIT_PRECEDING
     97                  | WalkerFactory.BIT_PRECEDING_SIBLING
     98                  | WalkerFactory.BIT_FOLLOWING
     99                  | WalkerFactory.BIT_FOLLOWING_SIBLING
    100                  | WalkerFactory.BIT_PARENT | WalkerFactory.BIT_FILTER)))
    101       walkBack = true;
    102 
    103     if (0 != (analysis
    104               & (WalkerFactory.BIT_DESCENDANT_OR_SELF
    105                  | WalkerFactory.BIT_DESCENDANT
    106                  | WalkerFactory.BIT_CHILD)))
    107       walkDescendants = true;
    108 
    109     if (0 != (analysis
    110               & (WalkerFactory.BIT_ATTRIBUTE | WalkerFactory.BIT_NAMESPACE)))
    111       walkAttributes = true;
    112 
    113     if(false || DEBUG)
    114     {
    115       System.out.print("analysis: "+Integer.toBinaryString(analysis));
    116       System.out.println(", "+WalkerFactory.getAnalysisString(analysis));
    117     }
    118 
    119     if(fromRoot || walkBack)
    120     {
    121       if(walkAttributes)
    122       {
    123         m_superAxis = Axis.ALL;
    124       }
    125       else
    126       {
    127         m_superAxis = Axis.DESCENDANTSFROMROOT;
    128       }
    129     }
    130     else if(walkDescendants)
    131     {
    132       if(walkAttributes)
    133       {
    134         m_superAxis = Axis.ALLFROMNODE;
    135       }
    136       else
    137       {
    138         m_superAxis = Axis.DESCENDANTORSELF;
    139       }
    140     }
    141     else
    142     {
    143       m_superAxis = Axis.ALL;
    144     }
    145     if(false || DEBUG)
    146     {
    147       System.out.println("axis: "+Axis.getNames(m_superAxis));
    148     }
    149 
    150   }
    151 
    152 
    153   /**
    154    * Initialize the context values for this expression
    155    * after it is cloned.
    156    *
    157    * @param context The XPath runtime context for this
    158    * transformation.
    159    */
    160   public void setRoot(int context, Object environment)
    161   {
    162     super.setRoot(context, environment);
    163     m_traverser = m_cdtm.getAxisTraverser(m_superAxis);
    164   }
    165 
    166   /**
    167    *  Detaches the iterator from the set which it iterated over, releasing
    168    * any computational resources and placing the iterator in the INVALID
    169    * state. After<code>detach</code> has been invoked, calls to
    170    * <code>nextNode</code> or<code>previousNode</code> will raise the
    171    * exception INVALID_STATE_ERR.
    172    */
    173   public void detach()
    174   {
    175     if(m_allowDetach)
    176     {
    177       m_traverser = null;
    178 
    179       // Always call the superclass detach last!
    180       super.detach();
    181     }
    182   }
    183 
    184   /**
    185    * Get the next node via getNextXXX.  Bottlenecked for derived class override.
    186    * @return The next node on the axis, or DTM.NULL.
    187    */
    188   protected int getNextNode()
    189   {
    190     m_lastFetched = (DTM.NULL == m_lastFetched)
    191                      ? m_traverser.first(m_context)
    192                      : m_traverser.next(m_context, m_lastFetched);
    193     return m_lastFetched;
    194   }
    195 
    196   /**
    197    *  Returns the next node in the set and advances the position of the
    198    * iterator in the set. After a NodeIterator is created, the first call
    199    * to nextNode() returns the first node in the set.
    200    * @return  The next <code>Node</code> in the set being iterated over, or
    201    *   <code>null</code> if there are no more members in that set.
    202    */
    203   public int nextNode()
    204   {
    205   	if(m_foundLast)
    206   		return DTM.NULL;
    207 
    208     int next;
    209 
    210     org.apache.xpath.VariableStack vars;
    211     int savedStart;
    212     if (-1 != m_stackFrame)
    213     {
    214       vars = m_execContext.getVarStack();
    215 
    216       // These three statements need to be combined into one operation.
    217       savedStart = vars.getStackFrame();
    218 
    219       vars.setStackFrame(m_stackFrame);
    220     }
    221     else
    222     {
    223       // Yuck.  Just to shut up the compiler!
    224       vars = null;
    225       savedStart = 0;
    226     }
    227 
    228     try
    229     {
    230       if(DEBUG)
    231         System.out.println("m_pattern"+m_pattern.toString());
    232 
    233       do
    234       {
    235         next = getNextNode();
    236 
    237         if (DTM.NULL != next)
    238         {
    239           if(DTMIterator.FILTER_ACCEPT == acceptNode(next, m_execContext))
    240             break;
    241           else
    242             continue;
    243         }
    244         else
    245           break;
    246       }
    247       while (next != DTM.NULL);
    248 
    249       if (DTM.NULL != next)
    250       {
    251         if(DEBUG)
    252         {
    253           System.out.println("next: "+next);
    254           System.out.println("name: "+m_cdtm.getNodeName(next));
    255         }
    256         incrementCurrentPos();
    257 
    258         return next;
    259       }
    260       else
    261       {
    262         m_foundLast = true;
    263 
    264         return DTM.NULL;
    265       }
    266     }
    267     finally
    268     {
    269       if (-1 != m_stackFrame)
    270       {
    271         // These two statements need to be combined into one operation.
    272         vars.setStackFrame(savedStart);
    273       }
    274     }
    275 
    276   }
    277 
    278   /**
    279    *  Test whether a specified node is visible in the logical view of a
    280    * TreeWalker or NodeIterator. This function will be called by the
    281    * implementation of TreeWalker and NodeIterator; it is not intended to
    282    * be called directly from user code.
    283    * @param n  The node to check to see if it passes the filter or not.
    284    * @return  a constant to determine whether the node is accepted,
    285    *   rejected, or skipped, as defined  above .
    286    */
    287   public short acceptNode(int n, XPathContext xctxt)
    288   {
    289 
    290     try
    291     {
    292       xctxt.pushCurrentNode(n);
    293       xctxt.pushIteratorRoot(m_context);
    294       if(DEBUG)
    295       {
    296         System.out.println("traverser: "+m_traverser);
    297         System.out.print("node: "+n);
    298         System.out.println(", "+m_cdtm.getNodeName(n));
    299         // if(m_cdtm.getNodeName(n).equals("near-east"))
    300         System.out.println("pattern: "+m_pattern.toString());
    301         m_pattern.debugWhatToShow(m_pattern.getWhatToShow());
    302       }
    303 
    304       XObject score = m_pattern.execute(xctxt);
    305 
    306       if(DEBUG)
    307       {
    308         // System.out.println("analysis: "+Integer.toBinaryString(m_analysis));
    309         System.out.println("score: "+score);
    310         System.out.println("skip: "+(score == NodeTest.SCORE_NONE));
    311       }
    312 
    313       // System.out.println("\n::acceptNode - score: "+score.num()+"::");
    314       return (score == NodeTest.SCORE_NONE) ? DTMIterator.FILTER_SKIP
    315                     : DTMIterator.FILTER_ACCEPT;
    316     }
    317     catch (javax.xml.transform.TransformerException se)
    318     {
    319 
    320       // TODO: Fix this.
    321       throw new RuntimeException(se.getMessage());
    322     }
    323     finally
    324     {
    325       xctxt.popCurrentNode();
    326       xctxt.popIteratorRoot();
    327     }
    328 
    329   }
    330 
    331 }
    332