1. package org.apache.xpath.axes;
  2. import javax.xml.transform.TransformerException;
  3. import org.apache.xml.dtm.DTM;
  4. import org.apache.xml.dtm.DTMAxisIterator;
  5. import org.apache.xml.dtm.DTMFilter;
  6. import org.apache.xml.dtm.DTMIterator;
  7. import org.apache.xpath.Expression;
  8. import org.apache.xpath.XPathContext;
  9. import org.apache.xpath.compiler.Compiler;
  10. /**
  11. * <meta name="usage" content="advanced"/>
  12. * This class implements a general iterator for
  13. * those LocationSteps with only one step, and perhaps a predicate.
  14. * @see org.apache.xpath.axes.WalkerFactory#newLocPathIterator
  15. */
  16. public class OneStepIterator extends ChildTestIterator
  17. {
  18. /** The traversal axis from where the nodes will be filtered. */
  19. protected int m_axis = -1;
  20. /** The DTM inner traversal class, that corresponds to the super axis. */
  21. protected DTMAxisIterator m_iterator;
  22. /**
  23. * Create a OneStepIterator object.
  24. *
  25. * @param compiler A reference to the Compiler that contains the op map.
  26. * @param opPos The position within the op map, which contains the
  27. * location path expression for this itterator.
  28. *
  29. * @throws javax.xml.transform.TransformerException
  30. */
  31. OneStepIterator(Compiler compiler, int opPos, int analysis)
  32. throws javax.xml.transform.TransformerException
  33. {
  34. super(compiler, opPos, analysis);
  35. int firstStepPos = compiler.getFirstChildPos(opPos);
  36. m_axis = WalkerFactory.getAxisFromStep(compiler, firstStepPos);
  37. }
  38. /**
  39. * Create a OneStepIterator object.
  40. *
  41. * @param iterator The DTM iterator which this iterator will use.
  42. * @param axis One of Axis.Child, etc., or -1 if the axis is unknown.
  43. *
  44. * @throws javax.xml.transform.TransformerException
  45. */
  46. public OneStepIterator(DTMAxisIterator iterator, int axis)
  47. throws javax.xml.transform.TransformerException
  48. {
  49. super(null);
  50. m_iterator = iterator;
  51. m_axis = axis;
  52. int whatToShow = DTMFilter.SHOW_ALL;
  53. initNodeTest(whatToShow);
  54. }
  55. /**
  56. * Initialize the context values for this expression
  57. * after it is cloned.
  58. *
  59. * @param execContext The XPath runtime context for this
  60. * transformation.
  61. */
  62. public void setRoot(int context, Object environment)
  63. {
  64. super.setRoot(context, environment);
  65. if(m_axis > -1)
  66. m_iterator = m_cdtm.getAxisIterator(m_axis);
  67. m_iterator.setStartNode(m_context);
  68. }
  69. /**
  70. * Get the next node via getFirstAttribute && getNextAttribute.
  71. */
  72. protected int getNextNode()
  73. {
  74. return m_lastFetched = m_iterator.next();
  75. }
  76. /**
  77. * Get a cloned iterator.
  78. *
  79. * @return A new iterator that can be used without mutating this one.
  80. *
  81. * @throws CloneNotSupportedException
  82. */
  83. public Object clone() throws CloneNotSupportedException
  84. {
  85. // Do not access the location path itterator during this operation!
  86. OneStepIterator clone = (OneStepIterator) super.clone();
  87. if(m_iterator != null)
  88. {
  89. clone.m_iterator = m_iterator.cloneIterator();
  90. }
  91. return clone;
  92. }
  93. /**
  94. * Get a cloned Iterator that is reset to the beginning
  95. * of the query.
  96. *
  97. * @return A cloned NodeIterator set of the start of the query.
  98. *
  99. * @throws CloneNotSupportedException
  100. */
  101. public DTMIterator cloneWithReset() throws CloneNotSupportedException
  102. {
  103. OneStepIterator clone = (OneStepIterator) super.cloneWithReset();
  104. clone.m_iterator = m_iterator;
  105. return clone;
  106. }
  107. /**
  108. * Tells if this is a reverse axes. Overrides AxesWalker#isReverseAxes.
  109. *
  110. * @return true for this class.
  111. */
  112. public boolean isReverseAxes()
  113. {
  114. return m_iterator.isReverse();
  115. }
  116. /**
  117. * Get the current sub-context position. In order to do the
  118. * reverse axes count, for the moment this re-searches the axes
  119. * up to the predicate. An optimization on this is to cache
  120. * the nodes searched, but, for the moment, this case is probably
  121. * rare enough that the added complexity isn't worth it.
  122. *
  123. * @param predicateIndex The predicate index of the proximity position.
  124. *
  125. * @return The pridicate index, or -1.
  126. */
  127. protected int getProximityPosition(int predicateIndex)
  128. {
  129. if(!isReverseAxes())
  130. return super.getProximityPosition(predicateIndex);
  131. // A negative predicate index seems to occur with
  132. // (preceding-sibling::*|following-sibling::*)/ancestor::*[position()]/*[position()]
  133. // -sb
  134. if(predicateIndex < 0)
  135. return -1;
  136. if (m_proximityPositions[predicateIndex] <= 0)
  137. {
  138. XPathContext xctxt = getXPathContext();
  139. try
  140. {
  141. OneStepIterator clone = (OneStepIterator) this.clone();
  142. int root = getRoot();
  143. xctxt.pushCurrentNode(root);
  144. clone.setRoot(root, xctxt);
  145. // clone.setPredicateCount(predicateIndex);
  146. clone.m_predCount = predicateIndex;
  147. // Count 'em all
  148. int count = 1;
  149. int next;
  150. while (DTM.NULL != (next = clone.nextNode()))
  151. {
  152. count++;
  153. }
  154. m_proximityPositions[predicateIndex] += count;
  155. }
  156. catch (CloneNotSupportedException cnse)
  157. {
  158. // can't happen
  159. }
  160. finally
  161. {
  162. xctxt.popCurrentNode();
  163. }
  164. }
  165. return m_proximityPositions[predicateIndex];
  166. }
  167. /**
  168. * Count backwards one proximity position.
  169. *
  170. * @param i The predicate index.
  171. */
  172. protected void countProximityPosition(int i)
  173. {
  174. if(!isReverseAxes())
  175. super.countProximityPosition(i);
  176. else if (i < m_proximityPositions.length)
  177. m_proximityPositions[i]--;
  178. }
  179. /**
  180. * Reset the iterator.
  181. */
  182. public void reset()
  183. {
  184. super.reset();
  185. if(null != m_iterator)
  186. m_iterator.reset();
  187. }
  188. /**
  189. * Returns the axis being iterated, if it is known.
  190. *
  191. * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
  192. * types.
  193. */
  194. public int getAxis()
  195. {
  196. return m_axis;
  197. }
  198. /**
  199. * @see Expression#deepEquals(Expression)
  200. */
  201. public boolean deepEquals(Expression expr)
  202. {
  203. if(!super.deepEquals(expr))
  204. return false;
  205. if(m_axis != ((OneStepIterator)expr).m_axis)
  206. return false;
  207. return true;
  208. }
  209. }