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: DescendantIterator.java,v 1.22 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.Axis;
  21. import com.sun.org.apache.xml.internal.dtm.DTM;
  22. import com.sun.org.apache.xml.internal.dtm.DTMAxisTraverser;
  23. import com.sun.org.apache.xml.internal.dtm.DTMFilter;
  24. import com.sun.org.apache.xml.internal.dtm.DTMIterator;
  25. import com.sun.org.apache.xpath.internal.Expression;
  26. import com.sun.org.apache.xpath.internal.XPathContext;
  27. import com.sun.org.apache.xpath.internal.compiler.Compiler;
  28. import com.sun.org.apache.xpath.internal.compiler.OpCodes;
  29. import com.sun.org.apache.xpath.internal.patterns.NodeTest;
  30. /**
  31. * This class implements an optimized iterator for
  32. * descendant, descendant-or-self, or "//foo" patterns.
  33. * @see com.sun.org.apache.xpath.internal.axes.LocPathIterator
  34. * @xsl.usage advanced
  35. */
  36. public class DescendantIterator extends LocPathIterator
  37. {
  38. /**
  39. * Create a DescendantIterator object.
  40. *
  41. * @param compiler A reference to the Compiler that contains the op map.
  42. * @param opPos The position within the op map, which contains the
  43. * location path expression for this itterator.
  44. *
  45. * @throws javax.xml.transform.TransformerException
  46. */
  47. DescendantIterator(Compiler compiler, int opPos, int analysis)
  48. throws javax.xml.transform.TransformerException
  49. {
  50. super(compiler, opPos, analysis, false);
  51. int firstStepPos = compiler.getFirstChildPos(opPos);
  52. int stepType = compiler.getOp(firstStepPos);
  53. boolean orSelf = (OpCodes.FROM_DESCENDANTS_OR_SELF == stepType);
  54. boolean fromRoot = false;
  55. if (OpCodes.FROM_SELF == stepType)
  56. {
  57. orSelf = true;
  58. // firstStepPos += 8;
  59. }
  60. else if(OpCodes.FROM_ROOT == stepType)
  61. {
  62. fromRoot = true;
  63. // Ugly code... will go away when AST work is done.
  64. int nextStepPos = compiler.getNextStepPos(firstStepPos);
  65. if(compiler.getOp(nextStepPos) == OpCodes.FROM_DESCENDANTS_OR_SELF)
  66. orSelf = true;
  67. // firstStepPos += 8;
  68. }
  69. // Find the position of the last step.
  70. int nextStepPos = firstStepPos;
  71. while(true)
  72. {
  73. nextStepPos = compiler.getNextStepPos(nextStepPos);
  74. if(nextStepPos > 0)
  75. {
  76. int stepOp = compiler.getOp(nextStepPos);
  77. if(OpCodes.ENDOP != stepOp)
  78. firstStepPos = nextStepPos;
  79. else
  80. break;
  81. }
  82. else
  83. break;
  84. }
  85. // Fix for http://nagoya.apache.org/bugzilla/show_bug.cgi?id=1336
  86. if((analysis & WalkerFactory.BIT_CHILD) != 0)
  87. orSelf = false;
  88. if(fromRoot)
  89. {
  90. if(orSelf)
  91. m_axis = Axis.DESCENDANTSORSELFFROMROOT;
  92. else
  93. m_axis = Axis.DESCENDANTSFROMROOT;
  94. }
  95. else if(orSelf)
  96. m_axis = Axis.DESCENDANTORSELF;
  97. else
  98. m_axis = Axis.DESCENDANT;
  99. int whatToShow = compiler.getWhatToShow(firstStepPos);
  100. if ((0 == (whatToShow
  101. & (DTMFilter.SHOW_ATTRIBUTE | DTMFilter.SHOW_ELEMENT
  102. | DTMFilter.SHOW_PROCESSING_INSTRUCTION))) ||
  103. (whatToShow == DTMFilter.SHOW_ALL))
  104. initNodeTest(whatToShow);
  105. else
  106. {
  107. initNodeTest(whatToShow, compiler.getStepNS(firstStepPos),
  108. compiler.getStepLocalName(firstStepPos));
  109. }
  110. initPredicateInfo(compiler, firstStepPos);
  111. }
  112. /**
  113. * Create a DescendantIterator object.
  114. *
  115. * @param compiler A reference to the Compiler that contains the op map.
  116. * @param opPos The position within the op map, which contains the
  117. * location path expression for this itterator.
  118. *
  119. * @throws javax.xml.transform.TransformerException
  120. */
  121. public DescendantIterator()
  122. {
  123. super(null);
  124. m_axis = Axis.DESCENDANTSORSELFFROMROOT;
  125. int whatToShow = DTMFilter.SHOW_ALL;
  126. initNodeTest(whatToShow);
  127. }
  128. /**
  129. * Get a cloned Iterator that is reset to the beginning
  130. * of the query.
  131. *
  132. * @return A cloned NodeIterator set of the start of the query.
  133. *
  134. * @throws CloneNotSupportedException
  135. */
  136. public DTMIterator cloneWithReset() throws CloneNotSupportedException
  137. {
  138. DescendantIterator clone = (DescendantIterator) super.cloneWithReset();
  139. clone.m_traverser = m_traverser;
  140. clone.resetProximityPositions();
  141. return clone;
  142. }
  143. /**
  144. * Returns the next node in the set and advances the position of the
  145. * iterator in the set. After a NodeIterator is created, the first call
  146. * to nextNode() returns the first node in the set.
  147. *
  148. * @return The next <code>Node</code> in the set being iterated over, or
  149. * <code>null</code> if there are no more members in that set.
  150. *
  151. * @throws DOMException
  152. * INVALID_STATE_ERR: Raised if this method is called after the
  153. * <code>detach</code> method was invoked.
  154. */
  155. public int nextNode()
  156. {
  157. if(m_foundLast)
  158. return DTM.NULL;
  159. if(DTM.NULL == m_lastFetched)
  160. {
  161. resetProximityPositions();
  162. }
  163. int next;
  164. com.sun.org.apache.xpath.internal.VariableStack vars;
  165. int savedStart;
  166. if (-1 != m_stackFrame)
  167. {
  168. vars = m_execContext.getVarStack();
  169. // These three statements need to be combined into one operation.
  170. savedStart = vars.getStackFrame();
  171. vars.setStackFrame(m_stackFrame);
  172. }
  173. else
  174. {
  175. // Yuck. Just to shut up the compiler!
  176. vars = null;
  177. savedStart = 0;
  178. }
  179. try
  180. {
  181. do
  182. {
  183. if(0 == m_extendedTypeID)
  184. {
  185. next = m_lastFetched = (DTM.NULL == m_lastFetched)
  186. ? m_traverser.first(m_context)
  187. : m_traverser.next(m_context, m_lastFetched);
  188. }
  189. else
  190. {
  191. next = m_lastFetched = (DTM.NULL == m_lastFetched)
  192. ? m_traverser.first(m_context, m_extendedTypeID)
  193. : m_traverser.next(m_context, m_lastFetched,
  194. m_extendedTypeID);
  195. }
  196. if (DTM.NULL != next)
  197. {
  198. if(DTMIterator.FILTER_ACCEPT == acceptNode(next))
  199. break;
  200. else
  201. continue;
  202. }
  203. else
  204. break;
  205. }
  206. while (next != DTM.NULL);
  207. if (DTM.NULL != next)
  208. {
  209. m_pos++;
  210. return next;
  211. }
  212. else
  213. {
  214. m_foundLast = true;
  215. return DTM.NULL;
  216. }
  217. }
  218. finally
  219. {
  220. if (-1 != m_stackFrame)
  221. {
  222. // These two statements need to be combined into one operation.
  223. vars.setStackFrame(savedStart);
  224. }
  225. }
  226. }
  227. /**
  228. * Initialize the context values for this expression
  229. * after it is cloned.
  230. *
  231. * @param execContext The XPath runtime context for this
  232. * transformation.
  233. */
  234. public void setRoot(int context, Object environment)
  235. {
  236. super.setRoot(context, environment);
  237. m_traverser = m_cdtm.getAxisTraverser(m_axis);
  238. String localName = getLocalName();
  239. String namespace = getNamespace();
  240. int what = m_whatToShow;
  241. // System.out.println("what: ");
  242. // NodeTest.debugWhatToShow(what);
  243. if(DTMFilter.SHOW_ALL == what
  244. || localName == NodeTest.WILD
  245. || namespace == NodeTest.WILD)
  246. {
  247. m_extendedTypeID = 0;
  248. }
  249. else
  250. {
  251. int type = getNodeTypeTest(what);
  252. m_extendedTypeID = m_cdtm.getExpandedTypeID(namespace, localName, type);
  253. }
  254. }
  255. /**
  256. * Return the first node out of the nodeset, if this expression is
  257. * a nodeset expression. This is the default implementation for
  258. * nodesets.
  259. * <p>WARNING: Do not mutate this class from this function!</p>
  260. * @param xctxt The XPath runtime context.
  261. * @return the first node out of the nodeset, or DTM.NULL.
  262. */
  263. public int asNode(XPathContext xctxt)
  264. throws javax.xml.transform.TransformerException
  265. {
  266. if(getPredicateCount() > 0)
  267. return super.asNode(xctxt);
  268. int current = xctxt.getCurrentNode();
  269. DTM dtm = xctxt.getDTM(current);
  270. DTMAxisTraverser traverser = dtm.getAxisTraverser(m_axis);
  271. String localName = getLocalName();
  272. String namespace = getNamespace();
  273. int what = m_whatToShow;
  274. // System.out.print(" (DescendantIterator) ");
  275. // System.out.println("what: ");
  276. // NodeTest.debugWhatToShow(what);
  277. if(DTMFilter.SHOW_ALL == what
  278. || localName == NodeTest.WILD
  279. || namespace == NodeTest.WILD)
  280. {
  281. return traverser.first(current);
  282. }
  283. else
  284. {
  285. int type = getNodeTypeTest(what);
  286. int extendedType = dtm.getExpandedTypeID(namespace, localName, type);
  287. return traverser.first(current, extendedType);
  288. }
  289. }
  290. /**
  291. * Detaches the iterator from the set which it iterated over, releasing
  292. * any computational resources and placing the iterator in the INVALID
  293. * state. After<code>detach</code> has been invoked, calls to
  294. * <code>nextNode</code> or<code>previousNode</code> will raise the
  295. * exception INVALID_STATE_ERR.
  296. */
  297. public void detach()
  298. {
  299. if (m_allowDetach) {
  300. m_traverser = null;
  301. m_extendedTypeID = 0;
  302. // Always call the superclass detach last!
  303. super.detach();
  304. }
  305. }
  306. /**
  307. * Returns the axis being iterated, if it is known.
  308. *
  309. * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
  310. * types.
  311. */
  312. public int getAxis()
  313. {
  314. return m_axis;
  315. }
  316. /** The traverser to use to navigate over the descendants. */
  317. transient protected DTMAxisTraverser m_traverser;
  318. /** The axis that we are traversing. */
  319. protected int m_axis;
  320. /** The extended type ID, not set until setRoot. */
  321. protected int m_extendedTypeID;
  322. /**
  323. * @see Expression#deepEquals(Expression)
  324. */
  325. public boolean deepEquals(Expression expr)
  326. {
  327. if(!super.deepEquals(expr))
  328. return false;
  329. if(m_axis != ((DescendantIterator)expr).m_axis)
  330. return false;
  331. return true;
  332. }
  333. }