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    */
WalkingIterator( Compiler compiler, int opPos, int analysis, boolean shouldLoadWalkers)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    */
WalkingIterator(PrefixResolver nscontext)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    */
getAnalysisBits()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    */
clone()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    */
reset()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    */
setRoot(int context, Object environment)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    */
nextNode()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    */
getFirstWalker()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    */
setFirstWalker(AxesWalker walker)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    */
setLastUsedWalker(AxesWalker walker)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    */
getLastUsedWalker()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    */
detach()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    */
fixupVariables(java.util.Vector vars, int globalsSize)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    */
callVisitors(ExpressionOwner owner, XPathVisitor visitor)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    */
getExpression()325   public Expression getExpression()
326   {
327     return m_firstWalker;
328   }
329 
330   /**
331    * @see ExpressionOwner#setExpression(Expression)
332    */
setExpression(Expression exp)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      */
deepEquals(Expression expr)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