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: MatchPatternIterator.java,v 1.8 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.DTMIterator;
  24. import com.sun.org.apache.xpath.internal.XPathContext;
  25. import com.sun.org.apache.xpath.internal.compiler.Compiler;
  26. import com.sun.org.apache.xpath.internal.objects.XObject;
  27. import com.sun.org.apache.xpath.internal.patterns.NodeTest;
  28. import com.sun.org.apache.xpath.internal.patterns.StepPattern;
  29. /**
  30. * This class treats a
  31. * <a href="http://www.w3.org/TR/xpath#location-paths">LocationPath</a> as a
  32. * filtered iteration over the tree, evaluating each node in a super axis
  33. * traversal against the LocationPath interpreted as a match pattern. This
  34. * class is useful to find nodes in document order that are complex paths
  35. * whose steps probably criss-cross each other.
  36. */
  37. public class MatchPatternIterator extends LocPathIterator
  38. {
  39. /** This is the select pattern, translated into a match pattern. */
  40. protected StepPattern m_pattern;
  41. /** The traversal axis from where the nodes will be filtered. */
  42. protected int m_superAxis = -1;
  43. /** The DTM inner traversal class, that corresponds to the super axis. */
  44. protected DTMAxisTraverser m_traverser;
  45. /** DEBUG flag for diagnostic dumps. */
  46. private static final boolean DEBUG = false;
  47. // protected int m_nsElemBase = DTM.NULL;
  48. /**
  49. * Create a LocPathIterator object, including creation
  50. * of step walkers from the opcode list, and call back
  51. * into the Compiler to create predicate expressions.
  52. *
  53. * @param compiler The Compiler which is creating
  54. * this expression.
  55. * @param opPos The position of this iterator in the
  56. * opcode list from the compiler.
  57. * @param analysis Analysis bits that give general information about the
  58. * LocationPath.
  59. *
  60. * @throws javax.xml.transform.TransformerException
  61. */
  62. MatchPatternIterator(Compiler compiler, int opPos, int analysis)
  63. throws javax.xml.transform.TransformerException
  64. {
  65. super(compiler, opPos, analysis, false);
  66. int firstStepPos = compiler.getFirstChildPos(opPos);
  67. m_pattern = WalkerFactory.loadSteps(this, compiler, firstStepPos, 0);
  68. boolean fromRoot = false;
  69. boolean walkBack = false;
  70. boolean walkDescendants = false;
  71. boolean walkAttributes = false;
  72. if (0 != (analysis & (WalkerFactory.BIT_ROOT |
  73. WalkerFactory.BIT_ANY_DESCENDANT_FROM_ROOT)))
  74. fromRoot = true;
  75. if (0 != (analysis
  76. & (WalkerFactory.BIT_ANCESTOR
  77. | WalkerFactory.BIT_ANCESTOR_OR_SELF
  78. | WalkerFactory.BIT_PRECEDING
  79. | WalkerFactory.BIT_PRECEDING_SIBLING
  80. | WalkerFactory.BIT_FOLLOWING
  81. | WalkerFactory.BIT_FOLLOWING_SIBLING
  82. | WalkerFactory.BIT_PARENT | WalkerFactory.BIT_FILTER)))
  83. walkBack = true;
  84. if (0 != (analysis
  85. & (WalkerFactory.BIT_DESCENDANT_OR_SELF
  86. | WalkerFactory.BIT_DESCENDANT
  87. | WalkerFactory.BIT_CHILD)))
  88. walkDescendants = true;
  89. if (0 != (analysis
  90. & (WalkerFactory.BIT_ATTRIBUTE | WalkerFactory.BIT_NAMESPACE)))
  91. walkAttributes = true;
  92. if(false || DEBUG)
  93. {
  94. System.out.print("analysis: "+Integer.toBinaryString(analysis));
  95. System.out.println(", "+WalkerFactory.getAnalysisString(analysis));
  96. }
  97. if(fromRoot || walkBack)
  98. {
  99. if(walkAttributes)
  100. {
  101. m_superAxis = Axis.ALL;
  102. }
  103. else
  104. {
  105. m_superAxis = Axis.DESCENDANTSFROMROOT;
  106. }
  107. }
  108. else if(walkDescendants)
  109. {
  110. if(walkAttributes)
  111. {
  112. m_superAxis = Axis.ALLFROMNODE;
  113. }
  114. else
  115. {
  116. m_superAxis = Axis.DESCENDANTORSELF;
  117. }
  118. }
  119. else
  120. {
  121. m_superAxis = Axis.ALL;
  122. }
  123. if(false || DEBUG)
  124. {
  125. System.out.println("axis: "+Axis.names[m_superAxis]);
  126. }
  127. }
  128. /**
  129. * Initialize the context values for this expression
  130. * after it is cloned.
  131. *
  132. * @param execContext The XPath runtime context for this
  133. * transformation.
  134. */
  135. public void setRoot(int context, Object environment)
  136. {
  137. super.setRoot(context, environment);
  138. m_traverser = m_cdtm.getAxisTraverser(m_superAxis);
  139. }
  140. /**
  141. * Detaches the iterator from the set which it iterated over, releasing
  142. * any computational resources and placing the iterator in the INVALID
  143. * state. After<code>detach</code> has been invoked, calls to
  144. * <code>nextNode</code> or<code>previousNode</code> will raise the
  145. * exception INVALID_STATE_ERR.
  146. */
  147. public void detach()
  148. {
  149. if(m_allowDetach)
  150. {
  151. m_traverser = null;
  152. // Always call the superclass detach last!
  153. super.detach();
  154. }
  155. }
  156. /**
  157. * Get the next node via getNextXXX. Bottlenecked for derived class override.
  158. * @return The next node on the axis, or DTM.NULL.
  159. */
  160. protected int getNextNode()
  161. {
  162. m_lastFetched = (DTM.NULL == m_lastFetched)
  163. ? m_traverser.first(m_context)
  164. : m_traverser.next(m_context, m_lastFetched);
  165. return m_lastFetched;
  166. }
  167. /**
  168. * Returns the next node in the set and advances the position of the
  169. * iterator in the set. After a NodeIterator is created, the first call
  170. * to nextNode() returns the first node in the set.
  171. * @return The next <code>Node</code> in the set being iterated over, or
  172. * <code>null</code> if there are no more members in that set.
  173. */
  174. public int nextNode()
  175. {
  176. if(m_foundLast)
  177. return DTM.NULL;
  178. int next;
  179. com.sun.org.apache.xpath.internal.VariableStack vars;
  180. int savedStart;
  181. if (-1 != m_stackFrame)
  182. {
  183. vars = m_execContext.getVarStack();
  184. // These three statements need to be combined into one operation.
  185. savedStart = vars.getStackFrame();
  186. vars.setStackFrame(m_stackFrame);
  187. }
  188. else
  189. {
  190. // Yuck. Just to shut up the compiler!
  191. vars = null;
  192. savedStart = 0;
  193. }
  194. try
  195. {
  196. if(DEBUG)
  197. System.out.println("m_pattern"+m_pattern.toString());
  198. do
  199. {
  200. next = getNextNode();
  201. if (DTM.NULL != next)
  202. {
  203. if(DTMIterator.FILTER_ACCEPT == acceptNode(next, m_execContext))
  204. break;
  205. else
  206. continue;
  207. }
  208. else
  209. break;
  210. }
  211. while (next != DTM.NULL);
  212. if (DTM.NULL != next)
  213. {
  214. if(DEBUG)
  215. {
  216. System.out.println("next: "+next);
  217. System.out.println("name: "+m_cdtm.getNodeName(next));
  218. }
  219. incrementCurrentPos();
  220. return next;
  221. }
  222. else
  223. {
  224. m_foundLast = true;
  225. return DTM.NULL;
  226. }
  227. }
  228. finally
  229. {
  230. if (-1 != m_stackFrame)
  231. {
  232. // These two statements need to be combined into one operation.
  233. vars.setStackFrame(savedStart);
  234. }
  235. }
  236. }
  237. /**
  238. * Test whether a specified node is visible in the logical view of a
  239. * TreeWalker or NodeIterator. This function will be called by the
  240. * implementation of TreeWalker and NodeIterator; it is not intended to
  241. * be called directly from user code.
  242. * @param n The node to check to see if it passes the filter or not.
  243. * @return a constant to determine whether the node is accepted,
  244. * rejected, or skipped, as defined above .
  245. */
  246. public short acceptNode(int n, XPathContext xctxt)
  247. {
  248. try
  249. {
  250. xctxt.pushCurrentNode(n);
  251. xctxt.pushIteratorRoot(m_context);
  252. if(DEBUG)
  253. {
  254. System.out.println("traverser: "+m_traverser);
  255. System.out.print("node: "+n);
  256. System.out.println(", "+m_cdtm.getNodeName(n));
  257. // if(m_cdtm.getNodeName(n).equals("near-east"))
  258. System.out.println("pattern: "+m_pattern.toString());
  259. m_pattern.debugWhatToShow(m_pattern.getWhatToShow());
  260. }
  261. XObject score = m_pattern.execute(xctxt);
  262. if(DEBUG)
  263. {
  264. // System.out.println("analysis: "+Integer.toBinaryString(m_analysis));
  265. System.out.println("score: "+score);
  266. System.out.println("skip: "+(score == NodeTest.SCORE_NONE));
  267. }
  268. // System.out.println("\n::acceptNode - score: "+score.num()+"::");
  269. return (score == NodeTest.SCORE_NONE) ? DTMIterator.FILTER_SKIP
  270. : DTMIterator.FILTER_ACCEPT;
  271. }
  272. catch (javax.xml.transform.TransformerException se)
  273. {
  274. // TODO: Fix this.
  275. throw new RuntimeException(se.getMessage());
  276. }
  277. finally
  278. {
  279. xctxt.popCurrentNode();
  280. xctxt.popIteratorRoot();
  281. }
  282. }
  283. }