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: ReverseAxesWalker.java,v 1.14 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.dtm.DTMAxisIterator;
  22. import com.sun.org.apache.xpath.internal.XPathContext;
  23. /**
  24. * Walker for a reverse axes.
  25. * @see <a href="http://www.w3.org/TR/xpath#predicates">XPath 2.4 Predicates</a>
  26. */
  27. public class ReverseAxesWalker extends AxesWalker
  28. {
  29. /**
  30. * Construct an AxesWalker using a LocPathIterator.
  31. *
  32. * @param locPathIterator The location path iterator that 'owns' this walker.
  33. */
  34. ReverseAxesWalker(LocPathIterator locPathIterator, int axis)
  35. {
  36. super(locPathIterator, axis);
  37. }
  38. /**
  39. * Set the root node of the TreeWalker.
  40. * (Not part of the DOM2 TreeWalker interface).
  41. *
  42. * @param root The context node of this step.
  43. */
  44. public void setRoot(int root)
  45. {
  46. super.setRoot(root);
  47. m_iterator = getDTM(root).getAxisIterator(m_axis);
  48. m_iterator.setStartNode(root);
  49. }
  50. /**
  51. * Detaches the walker from the set which it iterated over, releasing
  52. * any computational resources and placing the iterator in the INVALID
  53. * state.
  54. */
  55. public void detach()
  56. {
  57. m_iterator = null;
  58. super.detach();
  59. }
  60. /**
  61. * Get the next node in document order on the axes.
  62. *
  63. * @return the next node in document order on the axes, or null.
  64. */
  65. protected int getNextNode()
  66. {
  67. if (m_foundLast)
  68. return DTM.NULL;
  69. int next = m_iterator.next();
  70. if (m_isFresh)
  71. m_isFresh = false;
  72. if (DTM.NULL == next)
  73. this.m_foundLast = true;
  74. return next;
  75. }
  76. /**
  77. * Tells if this is a reverse axes. Overrides AxesWalker#isReverseAxes.
  78. *
  79. * @return true for this class.
  80. */
  81. public boolean isReverseAxes()
  82. {
  83. return true;
  84. }
  85. // /**
  86. // * Set the root node of the TreeWalker.
  87. // *
  88. // * @param root The context node of this step.
  89. // */
  90. // public void setRoot(int root)
  91. // {
  92. // super.setRoot(root);
  93. // }
  94. /**
  95. * Get the current sub-context position. In order to do the
  96. * reverse axes count, for the moment this re-searches the axes
  97. * up to the predicate. An optimization on this is to cache
  98. * the nodes searched, but, for the moment, this case is probably
  99. * rare enough that the added complexity isn't worth it.
  100. *
  101. * @param predicateIndex The predicate index of the proximity position.
  102. *
  103. * @return The pridicate index, or -1.
  104. */
  105. protected int getProximityPosition(int predicateIndex)
  106. {
  107. // A negative predicate index seems to occur with
  108. // (preceding-sibling::*|following-sibling::*)/ancestor::*[position()]/*[position()]
  109. // -sb
  110. if(predicateIndex < 0)
  111. return -1;
  112. int count = m_proximityPositions[predicateIndex];
  113. if (count <= 0)
  114. {
  115. AxesWalker savedWalker = wi().getLastUsedWalker();
  116. try
  117. {
  118. ReverseAxesWalker clone = (ReverseAxesWalker) this.clone();
  119. clone.setRoot(this.getRoot());
  120. clone.setPredicateCount(predicateIndex);
  121. clone.setPrevWalker(null);
  122. clone.setNextWalker(null);
  123. wi().setLastUsedWalker(clone);
  124. // Count 'em all
  125. count++;
  126. int next;
  127. while (DTM.NULL != (next = clone.nextNode()))
  128. {
  129. count++;
  130. }
  131. m_proximityPositions[predicateIndex] = count;
  132. }
  133. catch (CloneNotSupportedException cnse)
  134. {
  135. // can't happen
  136. }
  137. finally
  138. {
  139. wi().setLastUsedWalker(savedWalker);
  140. }
  141. }
  142. return count;
  143. }
  144. /**
  145. * Count backwards one proximity position.
  146. *
  147. * @param i The predicate index.
  148. */
  149. protected void countProximityPosition(int i)
  150. {
  151. if (i < m_proximityPositions.length)
  152. m_proximityPositions[i]--;
  153. }
  154. /**
  155. * Get the number of nodes in this node list. The function is probably ill
  156. * named?
  157. *
  158. *
  159. * @param xctxt The XPath runtime context.
  160. *
  161. * @return the number of nodes in this node list.
  162. */
  163. public int getLastPos(XPathContext xctxt)
  164. {
  165. int count = 0;
  166. AxesWalker savedWalker = wi().getLastUsedWalker();
  167. try
  168. {
  169. ReverseAxesWalker clone = (ReverseAxesWalker) this.clone();
  170. clone.setRoot(this.getRoot());
  171. clone.setPredicateCount(this.getPredicateCount() - 1);
  172. clone.setPrevWalker(null);
  173. clone.setNextWalker(null);
  174. wi().setLastUsedWalker(clone);
  175. // Count 'em all
  176. // count = 1;
  177. int next;
  178. while (DTM.NULL != (next = clone.nextNode()))
  179. {
  180. count++;
  181. }
  182. }
  183. catch (CloneNotSupportedException cnse)
  184. {
  185. // can't happen
  186. }
  187. finally
  188. {
  189. wi().setLastUsedWalker(savedWalker);
  190. }
  191. return count;
  192. }
  193. /**
  194. * Returns true if all the nodes in the iteration well be returned in document
  195. * order.
  196. * Warning: This can only be called after setRoot has been called!
  197. *
  198. * @return false.
  199. */
  200. public boolean isDocOrdered()
  201. {
  202. return false; // I think.
  203. }
  204. /** The DTM inner traversal class, that corresponds to the super axis. */
  205. protected DTMAxisIterator m_iterator;
  206. }