1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the  "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 /*
19  * $Id: FilterExprIteratorSimple.java 468655 2006-10-28 07:12:06Z minchau $
20  */
21 package org.apache.xpath.axes;
22 
23 import org.apache.xml.dtm.Axis;
24 import org.apache.xml.dtm.DTM;
25 import org.apache.xml.utils.PrefixResolver;
26 import org.apache.xpath.Expression;
27 import org.apache.xpath.ExpressionOwner;
28 import org.apache.xpath.VariableStack;
29 import org.apache.xpath.XPathContext;
30 import org.apache.xpath.XPathVisitor;
31 import org.apache.xpath.objects.XNodeSet;
32 
33 /**
34  * Class to use for one-step iteration that doesn't have a predicate, and
35  * doesn't need to set the context.
36  */
37 public class FilterExprIteratorSimple extends LocPathIterator
38 {
39     static final long serialVersionUID = -6978977187025375579L;
40   /** The contained expression. Should be non-null.
41    *  @serial   */
42   private Expression m_expr;
43 
44   /** The result of executing m_expr.  Needs to be deep cloned on clone op.  */
45   transient private XNodeSet m_exprObj;
46 
47   private boolean m_mustHardReset = false;
48   private boolean m_canDetachNodeset = true;
49 
50   /**
51    * Create a FilterExprIteratorSimple object.
52    *
53    */
FilterExprIteratorSimple()54   public FilterExprIteratorSimple()
55   {
56     super(null);
57   }
58 
59   /**
60    * Create a FilterExprIteratorSimple object.
61    *
62    */
FilterExprIteratorSimple(Expression expr)63   public FilterExprIteratorSimple(Expression expr)
64   {
65     super(null);
66     m_expr = expr;
67   }
68 
69   /**
70    * Initialize the context values for this expression
71    * after it is cloned.
72    *
73    * @param context The XPath runtime context for this
74    * transformation.
75    */
setRoot(int context, Object environment)76   public void setRoot(int context, Object environment)
77   {
78   	super.setRoot(context, environment);
79   	m_exprObj = executeFilterExpr(context, m_execContext, getPrefixResolver(),
80   	                  getIsTopLevel(), m_stackFrame, m_expr);
81   }
82 
83   /**
84    * Execute the expression.  Meant for reuse by other FilterExpr iterators
85    * that are not derived from this object.
86    */
executeFilterExpr(int context, XPathContext xctxt, PrefixResolver prefixResolver, boolean isTopLevel, int stackFrame, Expression expr )87   public static XNodeSet executeFilterExpr(int context, XPathContext xctxt,
88   												PrefixResolver prefixResolver,
89   												boolean isTopLevel,
90   												int stackFrame,
91   												Expression expr )
92     throws org.apache.xml.utils.WrappedRuntimeException
93   {
94     PrefixResolver savedResolver = xctxt.getNamespaceContext();
95     XNodeSet result = null;
96 
97     try
98     {
99       xctxt.pushCurrentNode(context);
100       xctxt.setNamespaceContext(prefixResolver);
101 
102       // The setRoot operation can take place with a reset operation,
103       // and so we may not be in the context of LocPathIterator#nextNode,
104       // so we have to set up the variable context, execute the expression,
105       // and then restore the variable context.
106 
107       if (isTopLevel)
108       {
109         // System.out.println("calling m_expr.execute(getXPathContext())");
110         VariableStack vars = xctxt.getVarStack();
111 
112         // These three statements need to be combined into one operation.
113         int savedStart = vars.getStackFrame();
114         vars.setStackFrame(stackFrame);
115 
116         result = (org.apache.xpath.objects.XNodeSet) expr.execute(xctxt);
117         result.setShouldCacheNodes(true);
118 
119         // These two statements need to be combined into one operation.
120         vars.setStackFrame(savedStart);
121       }
122       else
123           result = (org.apache.xpath.objects.XNodeSet) expr.execute(xctxt);
124 
125     }
126     catch (javax.xml.transform.TransformerException se)
127     {
128 
129       // TODO: Fix...
130       throw new org.apache.xml.utils.WrappedRuntimeException(se);
131     }
132     finally
133     {
134       xctxt.popCurrentNode();
135       xctxt.setNamespaceContext(savedResolver);
136     }
137     return result;
138   }
139 
140   /**
141    *  Returns the next node in the set and advances the position of the
142    * iterator in the set. After a NodeIterator is created, the first call
143    * to nextNode() returns the first node in the set.
144    *
145    * @return  The next <code>Node</code> in the set being iterated over, or
146    *   <code>null</code> if there are no more members in that set.
147    */
nextNode()148   public int nextNode()
149   {
150   	if(m_foundLast)
151   		return DTM.NULL;
152 
153     int next;
154 
155     if (null != m_exprObj)
156     {
157       m_lastFetched = next = m_exprObj.nextNode();
158     }
159     else
160       m_lastFetched = next = DTM.NULL;
161 
162     // m_lastFetched = next;
163     if (DTM.NULL != next)
164     {
165       m_pos++;
166       return next;
167     }
168     else
169     {
170       m_foundLast = true;
171 
172       return DTM.NULL;
173     }
174   }
175 
176   /**
177    * Detaches the walker from the set which it iterated over, releasing
178    * any computational resources and placing the iterator in the INVALID
179    * state.
180    */
detach()181   public void detach()
182   {
183     if(m_allowDetach)
184     {
185   		super.detach();
186   		m_exprObj.detach();
187   		m_exprObj = null;
188     }
189   }
190 
191   /**
192    * This function is used to fixup variables from QNames to stack frame
193    * indexes at stylesheet build time.
194    * @param vars List of QNames that correspond to variables.  This list
195    * should be searched backwards for the first qualified name that
196    * corresponds to the variable reference qname.  The position of the
197    * QName in the vector from the start of the vector will be its position
198    * in the stack frame (but variables above the globalsTop value will need
199    * to be offset to the current stack frame).
200    */
fixupVariables(java.util.Vector vars, int globalsSize)201   public void fixupVariables(java.util.Vector vars, int globalsSize)
202   {
203     super.fixupVariables(vars, globalsSize);
204     m_expr.fixupVariables(vars, globalsSize);
205   }
206 
207   /**
208    * Get the inner contained expression of this filter.
209    */
getInnerExpression()210   public Expression getInnerExpression()
211   {
212     return m_expr;
213   }
214 
215   /**
216    * Set the inner contained expression of this filter.
217    */
setInnerExpression(Expression expr)218   public void setInnerExpression(Expression expr)
219   {
220     expr.exprSetParent(this);
221     m_expr = expr;
222   }
223 
224   /**
225    * Get the analysis bits for this walker, as defined in the WalkerFactory.
226    * @return One of WalkerFactory#BIT_DESCENDANT, etc.
227    */
getAnalysisBits()228   public int getAnalysisBits()
229   {
230     if (null != m_expr && m_expr instanceof PathComponent)
231     {
232       return ((PathComponent) m_expr).getAnalysisBits();
233     }
234     return WalkerFactory.BIT_FILTER;
235   }
236 
237   /**
238    * Returns true if all the nodes in the iteration well be returned in document
239    * order.
240    * Warning: This can only be called after setRoot has been called!
241    *
242    * @return true as a default.
243    */
isDocOrdered()244   public boolean isDocOrdered()
245   {
246     return m_exprObj.isDocOrdered();
247   }
248 
249   class filterExprOwner implements ExpressionOwner
250   {
251     /**
252     * @see ExpressionOwner#getExpression()
253     */
getExpression()254     public Expression getExpression()
255     {
256       return m_expr;
257     }
258 
259     /**
260      * @see ExpressionOwner#setExpression(Expression)
261      */
setExpression(Expression exp)262     public void setExpression(Expression exp)
263     {
264       exp.exprSetParent(FilterExprIteratorSimple.this);
265       m_expr = exp;
266     }
267 
268   }
269 
270   /**
271    * This will traverse the heararchy, calling the visitor for
272    * each member.  If the called visitor method returns
273    * false, the subtree should not be called.
274    *
275    * @param visitor The visitor whose appropriate method will be called.
276    */
callPredicateVisitors(XPathVisitor visitor)277   public void callPredicateVisitors(XPathVisitor visitor)
278   {
279     m_expr.callVisitors(new filterExprOwner(), visitor);
280 
281     super.callPredicateVisitors(visitor);
282   }
283 
284   /**
285    * @see Expression#deepEquals(Expression)
286    */
deepEquals(Expression expr)287   public boolean deepEquals(Expression expr)
288   {
289     if (!super.deepEquals(expr))
290       return false;
291 
292     FilterExprIteratorSimple fet = (FilterExprIteratorSimple) expr;
293     if (!m_expr.deepEquals(fet.m_expr))
294       return false;
295 
296     return true;
297   }
298 
299   /**
300    * Returns the axis being iterated, if it is known.
301    *
302    * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
303    * types.
304    */
getAxis()305   public int getAxis()
306   {
307   	if(null != m_exprObj)
308     	return m_exprObj.getAxis();
309     else
310     	return Axis.FILTEREDLIST;
311   }
312 
313 
314 }
315 
316