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: FilterExprWalker.java,v 1.24 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.DTMIterator;
  23. import com.sun.org.apache.xpath.internal.Expression;
  24. import com.sun.org.apache.xpath.internal.ExpressionOwner;
  25. import com.sun.org.apache.xpath.internal.XPathContext;
  26. import com.sun.org.apache.xpath.internal.XPathVisitor;
  27. import com.sun.org.apache.xpath.internal.compiler.Compiler;
  28. import com.sun.org.apache.xpath.internal.compiler.OpCodes;
  29. import com.sun.org.apache.xpath.internal.objects.XNodeSet;
  30. /**
  31. * Walker for the OP_VARIABLE, or OP_EXTFUNCTION, or OP_FUNCTION, or OP_GROUP,
  32. * op codes.
  33. * @see <a href="http://www.w3.org/TR/xpath#NT-FilterExpr">XPath FilterExpr descriptions</a>
  34. */
  35. public class FilterExprWalker extends AxesWalker
  36. {
  37. /**
  38. * Construct a FilterExprWalker using a LocPathIterator.
  39. *
  40. * @param locPathIterator non-null reference to the parent iterator.
  41. */
  42. public FilterExprWalker(WalkingIterator locPathIterator)
  43. {
  44. super(locPathIterator, Axis.FILTEREDLIST);
  45. }
  46. /**
  47. * Init a FilterExprWalker.
  48. *
  49. * @param compiler non-null reference to the Compiler that is constructing.
  50. * @param opPos positive opcode position for this step.
  51. * @param stepType The type of step.
  52. *
  53. * @throws javax.xml.transform.TransformerException
  54. */
  55. public void init(Compiler compiler, int opPos, int stepType)
  56. throws javax.xml.transform.TransformerException
  57. {
  58. super.init(compiler, opPos, stepType);
  59. // Smooth over an anomily in the opcode map...
  60. switch (stepType)
  61. {
  62. case OpCodes.OP_FUNCTION :
  63. case OpCodes.OP_EXTFUNCTION :
  64. m_mustHardReset = true;
  65. case OpCodes.OP_GROUP :
  66. case OpCodes.OP_VARIABLE :
  67. m_expr = compiler.compile(opPos);
  68. m_expr.exprSetParent(this);
  69. //if((OpCodes.OP_FUNCTION == stepType) && (m_expr instanceof com.sun.org.apache.xalan.internal.templates.FuncKey))
  70. if(m_expr instanceof com.sun.org.apache.xpath.internal.operations.Variable)
  71. {
  72. // hack/temp workaround
  73. m_canDetachNodeset = false;
  74. }
  75. break;
  76. default :
  77. m_expr = compiler.compile(opPos + 2);
  78. m_expr.exprSetParent(this);
  79. }
  80. // if(m_expr instanceof WalkingIterator)
  81. // {
  82. // WalkingIterator wi = (WalkingIterator)m_expr;
  83. // if(wi.getFirstWalker() instanceof FilterExprWalker)
  84. // {
  85. // FilterExprWalker fw = (FilterExprWalker)wi.getFirstWalker();
  86. // if(null == fw.getNextWalker())
  87. // {
  88. // m_expr = fw.m_expr;
  89. // m_expr.exprSetParent(this);
  90. // }
  91. // }
  92. //
  93. // }
  94. }
  95. /**
  96. * Detaches the walker from the set which it iterated over, releasing
  97. * any computational resources and placing the iterator in the INVALID
  98. * state.
  99. */
  100. public void detach()
  101. {
  102. super.detach();
  103. if (m_canDetachNodeset)
  104. {
  105. m_exprObj.detach();
  106. }
  107. m_exprObj = null;
  108. }
  109. /**
  110. * Set the root node of the TreeWalker.
  111. *
  112. * @param root non-null reference to the root, or starting point of
  113. * the query.
  114. */
  115. public void setRoot(int root)
  116. {
  117. super.setRoot(root);
  118. m_exprObj = FilterExprIteratorSimple.executeFilterExpr(root,
  119. m_lpi.getXPathContext(), m_lpi.getPrefixResolver(),
  120. m_lpi.getIsTopLevel(), m_lpi.m_stackFrame, m_expr);
  121. }
  122. /**
  123. * Get a cloned FilterExprWalker.
  124. *
  125. * @return A new FilterExprWalker that can be used without mutating this one.
  126. *
  127. * @throws CloneNotSupportedException
  128. */
  129. public Object clone() throws CloneNotSupportedException
  130. {
  131. FilterExprWalker clone = (FilterExprWalker) super.clone();
  132. // clone.m_expr = (Expression)((Expression)m_expr).clone();
  133. if (null != m_exprObj)
  134. clone.m_exprObj = (XNodeSet) m_exprObj.clone();
  135. return clone;
  136. }
  137. /**
  138. * This method needs to override AxesWalker.acceptNode because FilterExprWalkers
  139. * don't need to, and shouldn't, do a node test.
  140. * @param n The node to check to see if it passes the filter or not.
  141. * @return a constant to determine whether the node is accepted,
  142. * rejected, or skipped, as defined above .
  143. */
  144. public short acceptNode(int n)
  145. {
  146. try
  147. {
  148. if (getPredicateCount() > 0)
  149. {
  150. countProximityPosition(0);
  151. if (!executePredicates(n, m_lpi.getXPathContext()))
  152. return DTMIterator.FILTER_SKIP;
  153. }
  154. return DTMIterator.FILTER_ACCEPT;
  155. }
  156. catch (javax.xml.transform.TransformerException se)
  157. {
  158. throw new RuntimeException(se.getMessage());
  159. }
  160. }
  161. /**
  162. * Moves the <code>TreeWalker</code> to the next visible node in document
  163. * order relative to the current node, and returns the new node. If the
  164. * current node has no next node, or if the search for nextNode attempts
  165. * to step upward from the TreeWalker's root node, returns
  166. * <code>null</code> , and retains the current node.
  167. * @return The new node, or <code>null</code> if the current node has no
  168. * next node in the TreeWalker's logical view.
  169. */
  170. public int getNextNode()
  171. {
  172. if (null != m_exprObj)
  173. {
  174. int next = m_exprObj.nextNode();
  175. return next;
  176. }
  177. else
  178. return DTM.NULL;
  179. }
  180. /**
  181. * Get the index of the last node that can be itterated to.
  182. *
  183. *
  184. * @param xctxt XPath runtime context.
  185. *
  186. * @return the index of the last node that can be itterated to.
  187. */
  188. public int getLastPos(XPathContext xctxt)
  189. {
  190. return m_exprObj.getLength();
  191. }
  192. /** The contained expression. Should be non-null.
  193. * @serial */
  194. private Expression m_expr;
  195. /** The result of executing m_expr. Needs to be deep cloned on clone op. */
  196. transient private XNodeSet m_exprObj;
  197. private boolean m_mustHardReset = false;
  198. private boolean m_canDetachNodeset = true;
  199. /**
  200. * This function is used to fixup variables from QNames to stack frame
  201. * indexes at stylesheet build time.
  202. * @param vars List of QNames that correspond to variables. This list
  203. * should be searched backwards for the first qualified name that
  204. * corresponds to the variable reference qname. The position of the
  205. * QName in the vector from the start of the vector will be its position
  206. * in the stack frame (but variables above the globalsTop value will need
  207. * to be offset to the current stack frame).
  208. */
  209. public void fixupVariables(java.util.Vector vars, int globalsSize)
  210. {
  211. super.fixupVariables(vars, globalsSize);
  212. m_expr.fixupVariables(vars, globalsSize);
  213. }
  214. /**
  215. * Get the inner contained expression of this filter.
  216. */
  217. public Expression getInnerExpression()
  218. {
  219. return m_expr;
  220. }
  221. /**
  222. * Set the inner contained expression of this filter.
  223. */
  224. public void setInnerExpression(Expression expr)
  225. {
  226. expr.exprSetParent(this);
  227. m_expr = expr;
  228. }
  229. /**
  230. * Get the analysis bits for this walker, as defined in the WalkerFactory.
  231. * @return One of WalkerFactory#BIT_DESCENDANT, etc.
  232. */
  233. public int getAnalysisBits()
  234. {
  235. if (null != m_expr && m_expr instanceof PathComponent)
  236. {
  237. return ((PathComponent) m_expr).getAnalysisBits();
  238. }
  239. return WalkerFactory.BIT_FILTER;
  240. }
  241. /**
  242. * Returns true if all the nodes in the iteration well be returned in document
  243. * order.
  244. * Warning: This can only be called after setRoot has been called!
  245. *
  246. * @return true as a default.
  247. */
  248. public boolean isDocOrdered()
  249. {
  250. return m_exprObj.isDocOrdered();
  251. }
  252. /**
  253. * Returns the axis being iterated, if it is known.
  254. *
  255. * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
  256. * types.
  257. */
  258. public int getAxis()
  259. {
  260. return m_exprObj.getAxis();
  261. }
  262. class filterExprOwner implements ExpressionOwner
  263. {
  264. /**
  265. * @see ExpressionOwner#getExpression()
  266. */
  267. public Expression getExpression()
  268. {
  269. return m_expr;
  270. }
  271. /**
  272. * @see ExpressionOwner#setExpression(Expression)
  273. */
  274. public void setExpression(Expression exp)
  275. {
  276. exp.exprSetParent(FilterExprWalker.this);
  277. m_expr = exp;
  278. }
  279. }
  280. /**
  281. * This will traverse the heararchy, calling the visitor for
  282. * each member. If the called visitor method returns
  283. * false, the subtree should not be called.
  284. *
  285. * @param owner The owner of the visitor, where that path may be
  286. * rewritten if needed.
  287. * @param visitor The visitor whose appropriate method will be called.
  288. */
  289. public void callPredicateVisitors(XPathVisitor visitor)
  290. {
  291. m_expr.callVisitors(new filterExprOwner(), visitor);
  292. super.callPredicateVisitors(visitor);
  293. }
  294. /**
  295. * @see Expression#deepEquals(Expression)
  296. */
  297. public boolean deepEquals(Expression expr)
  298. {
  299. if (!super.deepEquals(expr))
  300. return false;
  301. FilterExprWalker walker = (FilterExprWalker)expr;
  302. if(!m_expr.deepEquals(walker.m_expr))
  303. return false;
  304. return true;
  305. }
  306. }