1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xalan" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, Lotus
  53. * Development Corporation., http://www.lotus.com. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package org.apache.xpath.axes;
  58. import javax.xml.transform.TransformerException;
  59. import org.apache.xml.dtm.Axis;
  60. import org.apache.xml.dtm.DTM;
  61. import org.apache.xml.dtm.DTMAxisTraverser;
  62. import org.apache.xml.dtm.DTMFilter;
  63. import org.apache.xml.dtm.DTMIterator;
  64. import org.apache.xpath.Expression;
  65. import org.apache.xpath.VariableStack;
  66. import org.apache.xpath.XPathContext;
  67. import org.apache.xpath.compiler.Compiler;
  68. import org.apache.xpath.compiler.OpCodes;
  69. import org.apache.xpath.patterns.NodeTest;
  70. /**
  71. * <meta name="usage" content="advanced"/>
  72. * This class implements an optimized iterator for
  73. * descendant, descendant-or-self, or "//foo" patterns.
  74. * @see org.apache.xpath.axes.WalkerFactory#newLocPathIterator
  75. */
  76. public class DescendantIterator extends LocPathIterator
  77. {
  78. /**
  79. * Create a DescendantIterator object.
  80. *
  81. * @param compiler A reference to the Compiler that contains the op map.
  82. * @param opPos The position within the op map, which contains the
  83. * location path expression for this itterator.
  84. *
  85. * @throws javax.xml.transform.TransformerException
  86. */
  87. DescendantIterator(Compiler compiler, int opPos, int analysis)
  88. throws javax.xml.transform.TransformerException
  89. {
  90. super(compiler, opPos, analysis, false);
  91. int firstStepPos = compiler.getFirstChildPos(opPos);
  92. int stepType = compiler.getOp(firstStepPos);
  93. boolean orSelf = (OpCodes.FROM_DESCENDANTS_OR_SELF == stepType);
  94. boolean fromRoot = false;
  95. if (OpCodes.FROM_SELF == stepType)
  96. {
  97. orSelf = true;
  98. // firstStepPos += 8;
  99. }
  100. else if(OpCodes.FROM_ROOT == stepType)
  101. {
  102. fromRoot = true;
  103. // Ugly code... will go away when AST work is done.
  104. int nextStepPos = compiler.getNextStepPos(firstStepPos);
  105. if(compiler.getOp(nextStepPos) == OpCodes.FROM_DESCENDANTS_OR_SELF)
  106. orSelf = true;
  107. // firstStepPos += 8;
  108. }
  109. // Find the position of the last step.
  110. int nextStepPos = firstStepPos;
  111. while(true)
  112. {
  113. nextStepPos = compiler.getNextStepPos(nextStepPos);
  114. if(nextStepPos > 0)
  115. {
  116. int stepOp = compiler.getOp(nextStepPos);
  117. if(OpCodes.ENDOP != stepOp)
  118. firstStepPos = nextStepPos;
  119. else
  120. break;
  121. }
  122. else
  123. break;
  124. }
  125. // Fix for http://nagoya.apache.org/bugzilla/show_bug.cgi?id=1336
  126. if((analysis & WalkerFactory.BIT_CHILD) != 0)
  127. orSelf = false;
  128. if(fromRoot)
  129. {
  130. if(orSelf)
  131. m_axis = Axis.DESCENDANTSORSELFFROMROOT;
  132. else
  133. m_axis = Axis.DESCENDANTSFROMROOT;
  134. }
  135. else if(orSelf)
  136. m_axis = Axis.DESCENDANTORSELF;
  137. else
  138. m_axis = Axis.DESCENDANT;
  139. int whatToShow = compiler.getWhatToShow(firstStepPos);
  140. if ((0 == (whatToShow
  141. & (DTMFilter.SHOW_ATTRIBUTE | DTMFilter.SHOW_ELEMENT
  142. | DTMFilter.SHOW_PROCESSING_INSTRUCTION))) ||
  143. (whatToShow == DTMFilter.SHOW_ALL))
  144. initNodeTest(whatToShow);
  145. else
  146. {
  147. initNodeTest(whatToShow, compiler.getStepNS(firstStepPos),
  148. compiler.getStepLocalName(firstStepPos));
  149. }
  150. initPredicateInfo(compiler, firstStepPos);
  151. }
  152. /**
  153. * Create a DescendantIterator object.
  154. *
  155. * @param compiler A reference to the Compiler that contains the op map.
  156. * @param opPos The position within the op map, which contains the
  157. * location path expression for this itterator.
  158. *
  159. * @throws javax.xml.transform.TransformerException
  160. */
  161. public DescendantIterator()
  162. {
  163. super(null);
  164. m_axis = Axis.DESCENDANTSORSELFFROMROOT;
  165. int whatToShow = DTMFilter.SHOW_ALL;
  166. initNodeTest(whatToShow);
  167. }
  168. /**
  169. * Get a cloned Iterator that is reset to the beginning
  170. * of the query.
  171. *
  172. * @return A cloned NodeIterator set of the start of the query.
  173. *
  174. * @throws CloneNotSupportedException
  175. */
  176. public DTMIterator cloneWithReset() throws CloneNotSupportedException
  177. {
  178. DescendantIterator clone = (DescendantIterator) super.cloneWithReset();
  179. clone.m_traverser = m_traverser;
  180. clone.resetProximityPositions();
  181. return clone;
  182. }
  183. /**
  184. * Returns the next node in the set and advances the position of the
  185. * iterator in the set. After a NodeIterator is created, the first call
  186. * to nextNode() returns the first node in the set.
  187. *
  188. * @return The next <code>Node</code> in the set being iterated over, or
  189. * <code>null</code> if there are no more members in that set.
  190. *
  191. * @throws DOMException
  192. * INVALID_STATE_ERR: Raised if this method is called after the
  193. * <code>detach</code> method was invoked.
  194. */
  195. public int nextNode()
  196. {
  197. if(m_foundLast)
  198. return DTM.NULL;
  199. if(DTM.NULL == m_lastFetched)
  200. {
  201. resetProximityPositions();
  202. }
  203. int next;
  204. org.apache.xpath.VariableStack vars;
  205. int savedStart;
  206. if (-1 != m_stackFrame)
  207. {
  208. vars = m_execContext.getVarStack();
  209. // These three statements need to be combined into one operation.
  210. savedStart = vars.getStackFrame();
  211. vars.setStackFrame(m_stackFrame);
  212. }
  213. else
  214. {
  215. // Yuck. Just to shut up the compiler!
  216. vars = null;
  217. savedStart = 0;
  218. }
  219. try
  220. {
  221. do
  222. {
  223. if(0 == m_extendedTypeID)
  224. {
  225. next = m_lastFetched = (DTM.NULL == m_lastFetched)
  226. ? m_traverser.first(m_context)
  227. : m_traverser.next(m_context, m_lastFetched);
  228. }
  229. else
  230. {
  231. next = m_lastFetched = (DTM.NULL == m_lastFetched)
  232. ? m_traverser.first(m_context, m_extendedTypeID)
  233. : m_traverser.next(m_context, m_lastFetched,
  234. m_extendedTypeID);
  235. }
  236. if (DTM.NULL != next)
  237. {
  238. if(DTMIterator.FILTER_ACCEPT == acceptNode(next))
  239. break;
  240. else
  241. continue;
  242. }
  243. else
  244. break;
  245. }
  246. while (next != DTM.NULL);
  247. if (DTM.NULL != next)
  248. {
  249. m_pos++;
  250. return next;
  251. }
  252. else
  253. {
  254. m_foundLast = true;
  255. return DTM.NULL;
  256. }
  257. }
  258. finally
  259. {
  260. if (-1 != m_stackFrame)
  261. {
  262. // These two statements need to be combined into one operation.
  263. vars.setStackFrame(savedStart);
  264. }
  265. }
  266. }
  267. /**
  268. * Initialize the context values for this expression
  269. * after it is cloned.
  270. *
  271. * @param execContext The XPath runtime context for this
  272. * transformation.
  273. */
  274. public void setRoot(int context, Object environment)
  275. {
  276. super.setRoot(context, environment);
  277. m_traverser = m_cdtm.getAxisTraverser(m_axis);
  278. String localName = getLocalName();
  279. String namespace = getNamespace();
  280. int what = m_whatToShow;
  281. // System.out.println("what: ");
  282. // NodeTest.debugWhatToShow(what);
  283. if(DTMFilter.SHOW_ALL == what
  284. || localName == NodeTest.WILD
  285. || namespace == NodeTest.WILD)
  286. {
  287. m_extendedTypeID = 0;
  288. }
  289. else
  290. {
  291. int type = getNodeTypeTest(what);
  292. m_extendedTypeID = m_cdtm.getExpandedTypeID(namespace, localName, type);
  293. }
  294. }
  295. /**
  296. * Return the first node out of the nodeset, if this expression is
  297. * a nodeset expression. This is the default implementation for
  298. * nodesets.
  299. * <p>WARNING: Do not mutate this class from this function!</p>
  300. * @param xctxt The XPath runtime context.
  301. * @return the first node out of the nodeset, or DTM.NULL.
  302. */
  303. public int asNode(XPathContext xctxt)
  304. throws javax.xml.transform.TransformerException
  305. {
  306. if(getPredicateCount() > 0)
  307. return super.asNode(xctxt);
  308. int current = xctxt.getCurrentNode();
  309. DTM dtm = xctxt.getDTM(current);
  310. DTMAxisTraverser traverser = dtm.getAxisTraverser(m_axis);
  311. String localName = getLocalName();
  312. String namespace = getNamespace();
  313. int what = m_whatToShow;
  314. // System.out.print(" (DescendantIterator) ");
  315. // System.out.println("what: ");
  316. // NodeTest.debugWhatToShow(what);
  317. if(DTMFilter.SHOW_ALL == what
  318. || localName == NodeTest.WILD
  319. || namespace == NodeTest.WILD)
  320. {
  321. return traverser.first(current);
  322. }
  323. else
  324. {
  325. int type = getNodeTypeTest(what);
  326. int extendedType = dtm.getExpandedTypeID(namespace, localName, type);
  327. return traverser.first(current, extendedType);
  328. }
  329. }
  330. /**
  331. * Detaches the iterator from the set which it iterated over, releasing
  332. * any computational resources and placing the iterator in the INVALID
  333. * state. After<code>detach</code> has been invoked, calls to
  334. * <code>nextNode</code> or<code>previousNode</code> will raise the
  335. * exception INVALID_STATE_ERR.
  336. */
  337. public void detach()
  338. {
  339. m_traverser = null;
  340. m_extendedTypeID = 0;
  341. // Always call the superclass detach last!
  342. super.detach();
  343. }
  344. /**
  345. * Returns the axis being iterated, if it is known.
  346. *
  347. * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
  348. * types.
  349. */
  350. public int getAxis()
  351. {
  352. return m_axis;
  353. }
  354. /** The traverser to use to navigate over the descendants. */
  355. transient protected DTMAxisTraverser m_traverser;
  356. /** The axis that we are traversing. */
  357. protected int m_axis;
  358. /** The extended type ID, not set until setRoot. */
  359. protected int m_extendedTypeID;
  360. /**
  361. * @see Expression#deepEquals(Expression)
  362. */
  363. public boolean deepEquals(Expression expr)
  364. {
  365. if(!super.deepEquals(expr))
  366. return false;
  367. if(m_axis != ((DescendantIterator)expr).m_axis)
  368. return false;
  369. return true;
  370. }
  371. }