001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 /*
019 * $Id: WalkingIterator.java 469314 2006-10-30 23:31:59Z minchau $
020 */
021 package org.apache.xpath.axes;
022
023 import org.apache.xml.dtm.DTM;
024 import org.apache.xml.utils.PrefixResolver;
025 import org.apache.xpath.Expression;
026 import org.apache.xpath.ExpressionOwner;
027 import org.apache.xpath.VariableStack;
028 import org.apache.xpath.XPathVisitor;
029 import org.apache.xpath.compiler.Compiler;
030 import org.apache.xpath.compiler.OpMap;
031
032 /**
033 * Location path iterator that uses Walkers.
034 */
035
036 public class WalkingIterator extends LocPathIterator implements ExpressionOwner
037 {
038 static final long serialVersionUID = 9110225941815665906L;
039 /**
040 * Create a WalkingIterator iterator, including creation
041 * of step walkers from the opcode list, and call back
042 * into the Compiler to create predicate expressions.
043 *
044 * @param compiler The Compiler which is creating
045 * this expression.
046 * @param opPos The position of this iterator in the
047 * opcode list from the compiler.
048 * @param shouldLoadWalkers True if walkers should be
049 * loaded, or false if this is a derived iterator and
050 * it doesn't wish to load child walkers.
051 *
052 * @throws javax.xml.transform.TransformerException
053 */
054 WalkingIterator(
055 Compiler compiler, int opPos, int analysis, boolean shouldLoadWalkers)
056 throws javax.xml.transform.TransformerException
057 {
058 super(compiler, opPos, analysis, shouldLoadWalkers);
059
060 int firstStepPos = OpMap.getFirstChildPos(opPos);
061
062 if (shouldLoadWalkers)
063 {
064 m_firstWalker = WalkerFactory.loadWalkers(this, compiler, firstStepPos, 0);
065 m_lastUsedWalker = m_firstWalker;
066 }
067 }
068
069 /**
070 * Create a WalkingIterator object.
071 *
072 * @param nscontext The namespace context for this iterator,
073 * should be OK if null.
074 */
075 public WalkingIterator(PrefixResolver nscontext)
076 {
077
078 super(nscontext);
079 }
080
081
082 /**
083 * Get the analysis bits for this walker, as defined in the WalkerFactory.
084 * @return One of WalkerFactory#BIT_DESCENDANT, etc.
085 */
086 public int getAnalysisBits()
087 {
088 int bits = 0;
089 if (null != m_firstWalker)
090 {
091 AxesWalker walker = m_firstWalker;
092
093 while (null != walker)
094 {
095 int bit = walker.getAnalysisBits();
096 bits |= bit;
097 walker = walker.getNextWalker();
098 }
099 }
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 }