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