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 java.util.Vector;
  59. import org.apache.xpath.axes.LocPathIterator;
  60. import org.apache.xpath.XPath;
  61. import org.apache.xpath.XPathContext;
  62. import org.apache.xpath.compiler.OpCodes;
  63. import org.apache.xpath.objects.XObject;
  64. import javax.xml.transform.TransformerException;
  65. import org.apache.xml.dtm.DTM;
  66. import org.apache.xml.dtm.DTMIterator;
  67. import org.apache.xml.dtm.DTMAxisIterator;
  68. import org.apache.xml.dtm.Axis;
  69. /**
  70. * Walker for a reverse axes.
  71. * @see <a href="http://www.w3.org/TR/xpath#predicates">XPath 2.4 Predicates</a>
  72. */
  73. public class ReverseAxesWalker extends AxesWalker
  74. {
  75. /**
  76. * Construct an AxesWalker using a LocPathIterator.
  77. *
  78. * @param locPathIterator The location path iterator that 'owns' this walker.
  79. */
  80. ReverseAxesWalker(LocPathIterator locPathIterator, int axis)
  81. {
  82. super(locPathIterator, axis);
  83. }
  84. /**
  85. * Set the root node of the TreeWalker.
  86. * (Not part of the DOM2 TreeWalker interface).
  87. *
  88. * @param root The context node of this step.
  89. */
  90. public void setRoot(int root)
  91. {
  92. super.setRoot(root);
  93. m_iterator = getDTM(root).getAxisIterator(m_axis);
  94. m_iterator.setStartNode(root);
  95. }
  96. /**
  97. * Get the next node in document order on the axes.
  98. *
  99. * @return the next node in document order on the axes, or null.
  100. */
  101. protected int getNextNode()
  102. {
  103. if (m_foundLast)
  104. return DTM.NULL;
  105. int next = m_iterator.next();
  106. if (m_isFresh)
  107. m_isFresh = false;
  108. if (DTM.NULL == next)
  109. this.m_foundLast = true;
  110. return next;
  111. }
  112. /**
  113. * Tells if this is a reverse axes. Overrides AxesWalker#isReverseAxes.
  114. *
  115. * @return true for this class.
  116. */
  117. public boolean isReverseAxes()
  118. {
  119. return true;
  120. }
  121. // /**
  122. // * Set the root node of the TreeWalker.
  123. // *
  124. // * @param root The context node of this step.
  125. // */
  126. // public void setRoot(int root)
  127. // {
  128. // super.setRoot(root);
  129. // }
  130. /**
  131. * Get the current sub-context position. In order to do the
  132. * reverse axes count, for the moment this re-searches the axes
  133. * up to the predicate. An optimization on this is to cache
  134. * the nodes searched, but, for the moment, this case is probably
  135. * rare enough that the added complexity isn't worth it.
  136. *
  137. * @param predicateIndex The predicate index of the proximity position.
  138. *
  139. * @return The pridicate index, or -1.
  140. */
  141. protected int getProximityPosition(int predicateIndex)
  142. {
  143. // A negative predicate index seems to occur with
  144. // (preceding-sibling::*|following-sibling::*)/ancestor::*[position()]/*[position()]
  145. // -sb
  146. if(predicateIndex < 0)
  147. return -1;
  148. int count = m_proximityPositions[predicateIndex];
  149. if (count <= 0)
  150. {
  151. AxesWalker savedWalker = wi().getLastUsedWalker();
  152. try
  153. {
  154. ReverseAxesWalker clone = (ReverseAxesWalker) this.clone();
  155. clone.setRoot(this.getRoot());
  156. clone.setPredicateCount(predicateIndex);
  157. clone.setPrevWalker(null);
  158. clone.setNextWalker(null);
  159. wi().setLastUsedWalker(clone);
  160. // Count 'em all
  161. count++;
  162. int next;
  163. while (DTM.NULL != (next = clone.nextNode()))
  164. {
  165. count++;
  166. }
  167. m_proximityPositions[predicateIndex] = count;
  168. }
  169. catch (CloneNotSupportedException cnse)
  170. {
  171. // can't happen
  172. }
  173. finally
  174. {
  175. wi().setLastUsedWalker(savedWalker);
  176. }
  177. }
  178. return count;
  179. }
  180. /**
  181. * Count backwards one proximity position.
  182. *
  183. * @param i The predicate index.
  184. */
  185. protected void countProximityPosition(int i)
  186. {
  187. if (i < m_proximityPositions.length)
  188. m_proximityPositions[i]--;
  189. }
  190. /**
  191. * Get the number of nodes in this node list. The function is probably ill
  192. * named?
  193. *
  194. *
  195. * @param xctxt The XPath runtime context.
  196. *
  197. * @return the number of nodes in this node list.
  198. */
  199. public int getLastPos(XPathContext xctxt)
  200. {
  201. int count = 0;
  202. AxesWalker savedWalker = wi().getLastUsedWalker();
  203. try
  204. {
  205. ReverseAxesWalker clone = (ReverseAxesWalker) this.clone();
  206. clone.setRoot(this.getRoot());
  207. clone.setPredicateCount(this.getPredicateCount() - 1);
  208. clone.setPrevWalker(null);
  209. clone.setNextWalker(null);
  210. wi().setLastUsedWalker(clone);
  211. // Count 'em all
  212. // count = 1;
  213. int next;
  214. while (DTM.NULL != (next = clone.nextNode()))
  215. {
  216. count++;
  217. }
  218. }
  219. catch (CloneNotSupportedException cnse)
  220. {
  221. // can't happen
  222. }
  223. finally
  224. {
  225. wi().setLastUsedWalker(savedWalker);
  226. }
  227. return count;
  228. }
  229. /**
  230. * Returns true if all the nodes in the iteration well be returned in document
  231. * order.
  232. * Warning: This can only be called after setRoot has been called!
  233. *
  234. * @return false.
  235. */
  236. public boolean isDocOrdered()
  237. {
  238. return false; // I think.
  239. }
  240. /** The DTM inner traversal class, that corresponds to the super axis. */
  241. protected DTMAxisIterator m_iterator;
  242. }