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: FilterExprIteratorSimple.java,v 1.5 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.utils.PrefixResolver;
  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.VariableStack;
  26. import com.sun.org.apache.xpath.internal.XPathContext;
  27. import com.sun.org.apache.xpath.internal.XPathVisitor;
  28. import com.sun.org.apache.xpath.internal.objects.XNodeSet;
  29. /**
  30. * Class to use for one-step iteration that doesn't have a predicate, and
  31. * doesn't need to set the context.
  32. */
  33. public class FilterExprIteratorSimple extends LocPathIterator
  34. {
  35. /** The contained expression. Should be non-null.
  36. * @serial */
  37. private Expression m_expr;
  38. /** The result of executing m_expr. Needs to be deep cloned on clone op. */
  39. transient private XNodeSet m_exprObj;
  40. private boolean m_mustHardReset = false;
  41. private boolean m_canDetachNodeset = true;
  42. /**
  43. * Create a ChildTestIterator object.
  44. *
  45. * @param traverser Traverser that tells how the KeyIterator is to be handled.
  46. *
  47. * @throws javax.xml.transform.TransformerException
  48. */
  49. public FilterExprIteratorSimple()
  50. {
  51. super(null);
  52. }
  53. /**
  54. * Create a ChildTestIterator object.
  55. *
  56. * @param traverser Traverser that tells how the KeyIterator is to be handled.
  57. *
  58. * @throws javax.xml.transform.TransformerException
  59. */
  60. public FilterExprIteratorSimple(Expression expr)
  61. {
  62. super(null);
  63. m_expr = expr;
  64. }
  65. /**
  66. * Initialize the context values for this expression
  67. * after it is cloned.
  68. *
  69. * @param execContext The XPath runtime context for this
  70. * transformation.
  71. */
  72. public void setRoot(int context, Object environment)
  73. {
  74. super.setRoot(context, environment);
  75. m_exprObj = executeFilterExpr(context, m_execContext, getPrefixResolver(),
  76. getIsTopLevel(), m_stackFrame, m_expr);
  77. }
  78. /**
  79. * Execute the expression. Meant for reuse by other FilterExpr iterators
  80. * that are not derived from this object.
  81. */
  82. public static XNodeSet executeFilterExpr(int context, XPathContext xctxt,
  83. PrefixResolver prefixResolver,
  84. boolean isTopLevel,
  85. int stackFrame,
  86. Expression expr )
  87. throws com.sun.org.apache.xml.internal.utils.WrappedRuntimeException
  88. {
  89. PrefixResolver savedResolver = xctxt.getNamespaceContext();
  90. XNodeSet result = null;
  91. try
  92. {
  93. xctxt.pushCurrentNode(context);
  94. xctxt.setNamespaceContext(prefixResolver);
  95. // The setRoot operation can take place with a reset operation,
  96. // and so we may not be in the context of LocPathIterator#nextNode,
  97. // so we have to set up the variable context, execute the expression,
  98. // and then restore the variable context.
  99. if (isTopLevel)
  100. {
  101. // System.out.println("calling m_expr.execute(getXPathContext())");
  102. VariableStack vars = xctxt.getVarStack();
  103. // These three statements need to be combined into one operation.
  104. int savedStart = vars.getStackFrame();
  105. vars.setStackFrame(stackFrame);
  106. result = (com.sun.org.apache.xpath.internal.objects.XNodeSet) expr.execute(xctxt);
  107. result.setShouldCacheNodes(true);
  108. // These two statements need to be combined into one operation.
  109. vars.setStackFrame(savedStart);
  110. }
  111. else
  112. result = (com.sun.org.apache.xpath.internal.objects.XNodeSet) expr.execute(xctxt);
  113. }
  114. catch (javax.xml.transform.TransformerException se)
  115. {
  116. // TODO: Fix...
  117. throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(se);
  118. }
  119. finally
  120. {
  121. xctxt.popCurrentNode();
  122. xctxt.setNamespaceContext(savedResolver);
  123. }
  124. return result;
  125. }
  126. /**
  127. * Returns the next node in the set and advances the position of the
  128. * iterator in the set. After a NodeIterator is created, the first call
  129. * to nextNode() returns the first node in the set.
  130. *
  131. * @return The next <code>Node</code> in the set being iterated over, or
  132. * <code>null</code> if there are no more members in that set.
  133. */
  134. public int nextNode()
  135. {
  136. if(m_foundLast)
  137. return DTM.NULL;
  138. int next;
  139. if (null != m_exprObj)
  140. {
  141. m_lastFetched = next = m_exprObj.nextNode();
  142. }
  143. else
  144. m_lastFetched = next = DTM.NULL;
  145. // m_lastFetched = next;
  146. if (DTM.NULL != next)
  147. {
  148. m_pos++;
  149. return next;
  150. }
  151. else
  152. {
  153. m_foundLast = true;
  154. return DTM.NULL;
  155. }
  156. }
  157. /**
  158. * Detaches the walker from the set which it iterated over, releasing
  159. * any computational resources and placing the iterator in the INVALID
  160. * state.
  161. */
  162. public void detach()
  163. {
  164. if(m_allowDetach)
  165. {
  166. super.detach();
  167. m_exprObj.detach();
  168. m_exprObj = null;
  169. }
  170. }
  171. /**
  172. * This function is used to fixup variables from QNames to stack frame
  173. * indexes at stylesheet build time.
  174. * @param vars List of QNames that correspond to variables. This list
  175. * should be searched backwards for the first qualified name that
  176. * corresponds to the variable reference qname. The position of the
  177. * QName in the vector from the start of the vector will be its position
  178. * in the stack frame (but variables above the globalsTop value will need
  179. * to be offset to the current stack frame).
  180. */
  181. public void fixupVariables(java.util.Vector vars, int globalsSize)
  182. {
  183. super.fixupVariables(vars, globalsSize);
  184. m_expr.fixupVariables(vars, globalsSize);
  185. }
  186. /**
  187. * Get the inner contained expression of this filter.
  188. */
  189. public Expression getInnerExpression()
  190. {
  191. return m_expr;
  192. }
  193. /**
  194. * Set the inner contained expression of this filter.
  195. */
  196. public void setInnerExpression(Expression expr)
  197. {
  198. expr.exprSetParent(this);
  199. m_expr = expr;
  200. }
  201. /**
  202. * Get the analysis bits for this walker, as defined in the WalkerFactory.
  203. * @return One of WalkerFactory#BIT_DESCENDANT, etc.
  204. */
  205. public int getAnalysisBits()
  206. {
  207. if (null != m_expr && m_expr instanceof PathComponent)
  208. {
  209. return ((PathComponent) m_expr).getAnalysisBits();
  210. }
  211. return WalkerFactory.BIT_FILTER;
  212. }
  213. /**
  214. * Returns true if all the nodes in the iteration well be returned in document
  215. * order.
  216. * Warning: This can only be called after setRoot has been called!
  217. *
  218. * @return true as a default.
  219. */
  220. public boolean isDocOrdered()
  221. {
  222. return m_exprObj.isDocOrdered();
  223. }
  224. class filterExprOwner implements ExpressionOwner
  225. {
  226. /**
  227. * @see ExpressionOwner#getExpression()
  228. */
  229. public Expression getExpression()
  230. {
  231. return m_expr;
  232. }
  233. /**
  234. * @see ExpressionOwner#setExpression(Expression)
  235. */
  236. public void setExpression(Expression exp)
  237. {
  238. exp.exprSetParent(FilterExprIteratorSimple.this);
  239. m_expr = exp;
  240. }
  241. }
  242. /**
  243. * This will traverse the heararchy, calling the visitor for
  244. * each member. If the called visitor method returns
  245. * false, the subtree should not be called.
  246. *
  247. * @param owner The owner of the visitor, where that path may be
  248. * rewritten if needed.
  249. * @param visitor The visitor whose appropriate method will be called.
  250. */
  251. public void callPredicateVisitors(XPathVisitor visitor)
  252. {
  253. m_expr.callVisitors(new filterExprOwner(), visitor);
  254. super.callPredicateVisitors(visitor);
  255. }
  256. /**
  257. * @see Expression#deepEquals(Expression)
  258. */
  259. public boolean deepEquals(Expression expr)
  260. {
  261. if (!super.deepEquals(expr))
  262. return false;
  263. FilterExprIteratorSimple fet = (FilterExprIteratorSimple) expr;
  264. if (!m_expr.deepEquals(fet.m_expr))
  265. return false;
  266. return true;
  267. }
  268. /**
  269. * Returns the axis being iterated, if it is known.
  270. *
  271. * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
  272. * types.
  273. */
  274. public int getAxis()
  275. {
  276. if(null != m_exprObj)
  277. return m_exprObj.getAxis();
  278. else
  279. return Axis.FILTEREDLIST;
  280. }
  281. }