OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / libcore / luni / src / main / java / org / apache / xpath / axes / OneStepIterator.java
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: OneStepIterator.java 469314 2006-10-30 23:31:59Z minchau $
20  */
21 package org.apache.xpath.axes;
22
23 import org.apache.xml.dtm.DTM;
24 import org.apache.xml.dtm.DTMAxisIterator;
25 import org.apache.xml.dtm.DTMFilter;
26 import org.apache.xml.dtm.DTMIterator;
27 import org.apache.xpath.Expression;
28 import org.apache.xpath.XPathContext;
29 import org.apache.xpath.compiler.Compiler;
30 import org.apache.xpath.compiler.OpMap;
31
32 /**
33  * This class implements a general iterator for
34  * those LocationSteps with only one step, and perhaps a predicate.
35  * @see org.apache.xpath.axes#LocPathIterator
36  * @xsl.usage advanced
37  */
38 public class OneStepIterator extends ChildTestIterator
39 {
40     static final long serialVersionUID = 4623710779664998283L;
41   /** The traversal axis from where the nodes will be filtered. */
42   protected int m_axis = -1;
43
44   /** The DTM inner traversal class, that corresponds to the super axis. */
45   protected DTMAxisIterator m_iterator;
46
47   /**
48    * Create a OneStepIterator object.
49    *
50    * @param compiler A reference to the Compiler that contains the op map.
51    * @param opPos The position within the op map, which contains the
52    * location path expression for this itterator.
53    *
54    * @throws javax.xml.transform.TransformerException
55    */
56   OneStepIterator(Compiler compiler, int opPos, int analysis)
57           throws javax.xml.transform.TransformerException
58   {
59     super(compiler, opPos, analysis);
60     int firstStepPos = OpMap.getFirstChildPos(opPos);
61     
62     m_axis = WalkerFactory.getAxisFromStep(compiler, firstStepPos);
63     
64   }
65   
66   
67   /**
68    * Create a OneStepIterator object.
69    *
70    * @param iterator The DTM iterator which this iterator will use.
71    * @param axis One of Axis.Child, etc., or -1 if the axis is unknown.
72    *
73    * @throws javax.xml.transform.TransformerException
74    */
75   public OneStepIterator(DTMAxisIterator iterator, int axis)
76           throws javax.xml.transform.TransformerException
77   {
78     super(null);
79     
80     m_iterator = iterator;
81     m_axis = axis;
82     int whatToShow = DTMFilter.SHOW_ALL;
83     initNodeTest(whatToShow);
84   }
85   
86   /**
87    * Initialize the context values for this expression
88    * after it is cloned.
89    *
90    * @param context The XPath runtime context for this
91    * transformation.
92    */
93   public void setRoot(int context, Object environment)
94   {
95     super.setRoot(context, environment);
96     if(m_axis > -1)
97       m_iterator = m_cdtm.getAxisIterator(m_axis);
98     m_iterator.setStartNode(m_context);
99   }
100
101   /**
102    *  Detaches the iterator from the set which it iterated over, releasing
103    * any computational resources and placing the iterator in the INVALID
104    * state. After<code>detach</code> has been invoked, calls to
105    * <code>nextNode</code> or<code>previousNode</code> will raise the
106    * exception INVALID_STATE_ERR.
107    */
108   public void detach()
109   {    
110     if(m_allowDetach)
111     {
112       if(m_axis > -1)
113         m_iterator = null;
114       
115       // Always call the superclass detach last!
116       super.detach();
117     }
118   }
119   
120   /**
121    * Get the next node via getFirstAttribute && getNextAttribute.
122    */
123   protected int getNextNode()
124   {
125     return m_lastFetched = m_iterator.next();
126   }
127   
128   /**
129    * Get a cloned iterator.
130    *
131    * @return A new iterator that can be used without mutating this one.
132    *
133    * @throws CloneNotSupportedException
134    */
135   public Object clone() throws CloneNotSupportedException
136   {
137     // Do not access the location path itterator during this operation!
138     
139     OneStepIterator clone = (OneStepIterator) super.clone();
140
141     if(m_iterator != null)
142     {
143       clone.m_iterator = m_iterator.cloneIterator();
144     }
145     return clone;
146   }
147   
148   /**
149    *  Get a cloned Iterator that is reset to the beginning
150    *  of the query.
151    * 
152    *  @return A cloned NodeIterator set of the start of the query.
153    * 
154    *  @throws CloneNotSupportedException
155    */
156   public DTMIterator cloneWithReset() throws CloneNotSupportedException
157   {
158
159     OneStepIterator clone = (OneStepIterator) super.cloneWithReset();
160     clone.m_iterator = m_iterator;
161
162     return clone;
163   }
164
165
166
167   /**
168    * Tells if this is a reverse axes.  Overrides AxesWalker#isReverseAxes.
169    *
170    * @return true for this class.
171    */
172   public boolean isReverseAxes()
173   {
174     return m_iterator.isReverse();
175   }
176
177   /**
178    * Get the current sub-context position.  In order to do the
179    * reverse axes count, for the moment this re-searches the axes
180    * up to the predicate.  An optimization on this is to cache
181    * the nodes searched, but, for the moment, this case is probably
182    * rare enough that the added complexity isn't worth it.
183    *
184    * @param predicateIndex The predicate index of the proximity position.
185    *
186    * @return The pridicate index, or -1.
187    */
188   protected int getProximityPosition(int predicateIndex)
189   {
190     if(!isReverseAxes())
191       return super.getProximityPosition(predicateIndex);
192       
193     // A negative predicate index seems to occur with
194     // (preceding-sibling::*|following-sibling::*)/ancestor::*[position()]/*[position()]
195     // -sb
196     if(predicateIndex < 0)
197       return -1;
198       
199     if (m_proximityPositions[predicateIndex] <= 0)
200     {
201       XPathContext xctxt = getXPathContext();
202       try
203       {
204         OneStepIterator clone = (OneStepIterator) this.clone();
205         
206         int root = getRoot();
207         xctxt.pushCurrentNode(root);
208         clone.setRoot(root, xctxt);
209
210         // clone.setPredicateCount(predicateIndex);
211         clone.m_predCount = predicateIndex;
212
213         // Count 'em all
214         int count = 1;
215         int next;
216
217         while (DTM.NULL != (next = clone.nextNode()))
218         {
219           count++;
220         }
221
222         m_proximityPositions[predicateIndex] += count;
223       }
224       catch (CloneNotSupportedException cnse)
225       {
226
227         // can't happen
228       }
229       finally
230       {
231         xctxt.popCurrentNode();
232       }
233     }
234
235     return m_proximityPositions[predicateIndex];
236   }
237
238   /**
239    *  The number of nodes in the list. The range of valid child node indices
240    * is 0 to <code>length-1</code> inclusive.
241    *
242    * @return The number of nodes in the list, always greater or equal to zero.
243    */
244   public int getLength()
245   {
246     if(!isReverseAxes())
247       return super.getLength();
248       
249     // Tell if this is being called from within a predicate.
250     boolean isPredicateTest = (this == m_execContext.getSubContextList());
251
252     // And get how many total predicates are part of this step.
253     int predCount = getPredicateCount();
254    
255     // If we have already calculated the length, and the current predicate 
256     // is the first predicate, then return the length.  We don't cache 
257     // the anything but the length of the list to the first predicate.
258     if (-1 != m_length && isPredicateTest && m_predicateIndex < 1)
259        return m_length;      
260
261     int count = 0;
262     
263     XPathContext xctxt = getXPathContext();
264     try
265     {
266       OneStepIterator clone = (OneStepIterator) this.cloneWithReset();
267       
268       int root = getRoot();
269       xctxt.pushCurrentNode(root);
270       clone.setRoot(root, xctxt);
271  
272       clone.m_predCount = m_predicateIndex;
273
274       int next;
275
276       while (DTM.NULL != (next = clone.nextNode()))
277       {
278         count++;
279       }
280     }
281     catch (CloneNotSupportedException cnse)
282     {
283        // can't happen
284     }
285     finally
286     {
287       xctxt.popCurrentNode();
288     }
289     if (isPredicateTest && m_predicateIndex < 1)
290       m_length = count;    
291       
292     return count;
293   }
294
295   /**
296    * Count backwards one proximity position.
297    *
298    * @param i The predicate index.
299    */
300   protected void countProximityPosition(int i)
301   {
302     if(!isReverseAxes())
303       super.countProximityPosition(i);
304     else if (i < m_proximityPositions.length)
305       m_proximityPositions[i]--;
306   }
307   
308   /**
309    * Reset the iterator.
310    */
311   public void reset()
312   {
313
314     super.reset();
315     if(null != m_iterator)
316       m_iterator.reset();
317   }
318   
319   /**
320    * Returns the axis being iterated, if it is known.
321    * 
322    * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple 
323    * types.
324    */
325   public int getAxis()
326   {
327     return m_axis;
328   }
329   
330   /**
331    * @see Expression#deepEquals(Expression)
332    */
333   public boolean deepEquals(Expression expr)
334   {
335         if(!super.deepEquals(expr))
336                 return false;
337                 
338         if(m_axis != ((OneStepIterator)expr).m_axis)
339                 return false;
340                 
341         return true;
342   }
343
344   
345 }