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