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