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: WalkingIterator.java 469314 2006-10-30 23:31:59Z minchau $
     20  */
     21 package org.apache.xpath.axes;
     22 
     23 import org.apache.xml.dtm.DTM;
     24 import org.apache.xml.utils.PrefixResolver;
     25 import org.apache.xpath.Expression;
     26 import org.apache.xpath.ExpressionOwner;
     27 import org.apache.xpath.VariableStack;
     28 import org.apache.xpath.XPathVisitor;
     29 import org.apache.xpath.compiler.Compiler;
     30 import org.apache.xpath.compiler.OpMap;
     31 
     32 /**
     33  * Location path iterator that uses Walkers.
     34  */
     35 
     36 public class WalkingIterator extends LocPathIterator implements ExpressionOwner
     37 {
     38     static final long serialVersionUID = 9110225941815665906L;
     39   /**
     40    * Create a WalkingIterator iterator, including creation
     41    * of step walkers from the opcode list, and call back
     42    * into the Compiler to create predicate expressions.
     43    *
     44    * @param compiler The Compiler which is creating
     45    * this expression.
     46    * @param opPos The position of this iterator in the
     47    * opcode list from the compiler.
     48    * @param shouldLoadWalkers True if walkers should be
     49    * loaded, or false if this is a derived iterator and
     50    * it doesn't wish to load child walkers.
     51    *
     52    * @throws javax.xml.transform.TransformerException
     53    */
     54   WalkingIterator(
     55           Compiler compiler, int opPos, int analysis, boolean shouldLoadWalkers)
     56             throws javax.xml.transform.TransformerException
     57   {
     58     super(compiler, opPos, analysis, shouldLoadWalkers);
     59 
     60     int firstStepPos = OpMap.getFirstChildPos(opPos);
     61 
     62     if (shouldLoadWalkers)
     63     {
     64       m_firstWalker = WalkerFactory.loadWalkers(this, compiler, firstStepPos, 0);
     65       m_lastUsedWalker = m_firstWalker;
     66     }
     67   }
     68 
     69   /**
     70    * Create a WalkingIterator object.
     71    *
     72    * @param nscontext The namespace context for this iterator,
     73    * should be OK if null.
     74    */
     75   public WalkingIterator(PrefixResolver nscontext)
     76   {
     77 
     78     super(nscontext);
     79   }
     80 
     81 
     82   /**
     83    * Get the analysis bits for this walker, as defined in the WalkerFactory.
     84    * @return One of WalkerFactory#BIT_DESCENDANT, etc.
     85    */
     86   public int getAnalysisBits()
     87   {
     88     int bits = 0;
     89     if (null != m_firstWalker)
     90     {
     91       AxesWalker walker = m_firstWalker;
     92 
     93       while (null != walker)
     94       {
     95         int bit = walker.getAnalysisBits();
     96         bits |= bit;
     97         walker = walker.getNextWalker();
     98       }
     99     }
    100     return bits;
    101   }
    102 
    103   /**
    104    * Get a cloned WalkingIterator that holds the same
    105    * position as this iterator.
    106    *
    107    * @return A clone of this iterator that holds the same node position.
    108    *
    109    * @throws CloneNotSupportedException
    110    */
    111   public Object clone() throws CloneNotSupportedException
    112   {
    113 
    114     WalkingIterator clone = (WalkingIterator) super.clone();
    115 
    116     //    clone.m_varStackPos = this.m_varStackPos;
    117     //    clone.m_varStackContext = this.m_varStackContext;
    118     if (null != m_firstWalker)
    119     {
    120       clone.m_firstWalker = m_firstWalker.cloneDeep(clone, null);
    121     }
    122 
    123     return clone;
    124   }
    125 
    126   /**
    127    * Reset the iterator.
    128    */
    129   public void reset()
    130   {
    131 
    132     super.reset();
    133 
    134     if (null != m_firstWalker)
    135     {
    136       m_lastUsedWalker = m_firstWalker;
    137 
    138       m_firstWalker.setRoot(m_context);
    139     }
    140 
    141   }
    142 
    143   /**
    144    * Initialize the context values for this expression
    145    * after it is cloned.
    146    *
    147    * @param context The XPath runtime context for this
    148    * transformation.
    149    */
    150   public void setRoot(int context, Object environment)
    151   {
    152 
    153     super.setRoot(context, environment);
    154 
    155     if(null != m_firstWalker)
    156     {
    157       m_firstWalker.setRoot(context);
    158       m_lastUsedWalker = m_firstWalker;
    159     }
    160   }
    161 
    162   /**
    163    *  Returns the next node in the set and advances the position of the
    164    * iterator in the set. After a NodeIterator is created, the first call
    165    * to nextNode() returns the first node in the set.
    166    * @return  The next <code>Node</code> in the set being iterated over, or
    167    *   <code>null</code> if there are no more members in that set.
    168    */
    169   public int nextNode()
    170   {
    171   	if(m_foundLast)
    172   		return DTM.NULL;
    173 
    174     // If the variable stack position is not -1, we'll have to
    175     // set our position in the variable stack, so our variable access
    176     // will be correct.  Iterators that are at the top level of the
    177     // expression need to reset the variable stack, while iterators
    178     // in predicates do not need to, and should not, since their execution
    179     // may be much later than top-level iterators.
    180     // m_varStackPos is set in setRoot, which is called
    181     // from the execute method.
    182     if (-1 == m_stackFrame)
    183     {
    184       return returnNextNode(m_firstWalker.nextNode());
    185     }
    186     else
    187     {
    188       VariableStack vars = m_execContext.getVarStack();
    189 
    190       // These three statements need to be combined into one operation.
    191       int savedStart = vars.getStackFrame();
    192 
    193       vars.setStackFrame(m_stackFrame);
    194 
    195       int n = returnNextNode(m_firstWalker.nextNode());
    196 
    197       // These two statements need to be combined into one operation.
    198       vars.setStackFrame(savedStart);
    199 
    200       return n;
    201     }
    202   }
    203 
    204 
    205   /**
    206    * Get the head of the walker list.
    207    *
    208    * @return The head of the walker list, or null
    209    * if this iterator does not implement walkers.
    210    * @xsl.usage advanced
    211    */
    212   public final AxesWalker getFirstWalker()
    213   {
    214     return m_firstWalker;
    215   }
    216 
    217   /**
    218    * Set the head of the walker list.
    219    *
    220    * @param walker Should be a valid AxesWalker.
    221    * @xsl.usage advanced
    222    */
    223   public final void setFirstWalker(AxesWalker walker)
    224   {
    225     m_firstWalker = walker;
    226   }
    227 
    228 
    229   /**
    230    * Set the last used walker.
    231    *
    232    * @param walker The last used walker, or null.
    233    * @xsl.usage advanced
    234    */
    235   public final void setLastUsedWalker(AxesWalker walker)
    236   {
    237     m_lastUsedWalker = walker;
    238   }
    239 
    240   /**
    241    * Get the last used walker.
    242    *
    243    * @return The last used walker, or null.
    244    * @xsl.usage advanced
    245    */
    246   public final AxesWalker getLastUsedWalker()
    247   {
    248     return m_lastUsedWalker;
    249   }
    250 
    251   /**
    252    *  Detaches the iterator from the set which it iterated over, releasing
    253    * any computational resources and placing the iterator in the INVALID
    254    * state. After<code>detach</code> has been invoked, calls to
    255    * <code>nextNode</code> or<code>previousNode</code> will raise the
    256    * exception INVALID_STATE_ERR.
    257    */
    258   public void detach()
    259   {
    260     if(m_allowDetach)
    261     {
    262 	  	AxesWalker walker = m_firstWalker;
    263 	    while (null != walker)
    264 	    {
    265 	      walker.detach();
    266 	      walker = walker.getNextWalker();
    267 	    }
    268 
    269 	    m_lastUsedWalker = null;
    270 
    271 	    // Always call the superclass detach last!
    272 	    super.detach();
    273     }
    274   }
    275 
    276   /**
    277    * This function is used to fixup variables from QNames to stack frame
    278    * indexes at stylesheet build time.
    279    * @param vars List of QNames that correspond to variables.  This list
    280    * should be searched backwards for the first qualified name that
    281    * corresponds to the variable reference qname.  The position of the
    282    * QName in the vector from the start of the vector will be its position
    283    * in the stack frame (but variables above the globalsTop value will need
    284    * to be offset to the current stack frame).
    285    */
    286   public void fixupVariables(java.util.Vector vars, int globalsSize)
    287   {
    288     m_predicateIndex = -1;
    289 
    290     AxesWalker walker = m_firstWalker;
    291 
    292     while (null != walker)
    293     {
    294       walker.fixupVariables(vars, globalsSize);
    295       walker = walker.getNextWalker();
    296     }
    297   }
    298 
    299   /**
    300    * @see org.apache.xpath.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
    301    */
    302   public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
    303   {
    304   	 	if(visitor.visitLocationPath(owner, this))
    305   	 	{
    306   	 		if(null != m_firstWalker)
    307   	 		{
    308   	 			m_firstWalker.callVisitors(this, visitor);
    309   	 		}
    310   	 	}
    311   }
    312 
    313 
    314   /** The last used step walker in the walker list.
    315    *  @serial */
    316   protected AxesWalker m_lastUsedWalker;
    317 
    318   /** The head of the step walker list.
    319    *  @serial */
    320   protected AxesWalker m_firstWalker;
    321 
    322   /**
    323    * @see ExpressionOwner#getExpression()
    324    */
    325   public Expression getExpression()
    326   {
    327     return m_firstWalker;
    328   }
    329 
    330   /**
    331    * @see ExpressionOwner#setExpression(Expression)
    332    */
    333   public void setExpression(Expression exp)
    334   {
    335   	exp.exprSetParent(this);
    336   	m_firstWalker = (AxesWalker)exp;
    337   }
    338 
    339     /**
    340      * @see Expression#deepEquals(Expression)
    341      */
    342     public boolean deepEquals(Expression expr)
    343     {
    344       if (!super.deepEquals(expr))
    345                 return false;
    346 
    347       AxesWalker walker1 = m_firstWalker;
    348       AxesWalker walker2 = ((WalkingIterator)expr).m_firstWalker;
    349       while ((null != walker1) && (null != walker2))
    350       {
    351         if(!walker1.deepEquals(walker2))
    352         	return false;
    353         walker1 = walker1.getNextWalker();
    354         walker2 = walker2.getNextWalker();
    355       }
    356 
    357       if((null != walker1) || (null != walker2))
    358       	return false;
    359 
    360       return true;
    361     }
    362 
    363 }
    364