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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 * $Id: OneStepIterator.java 469314 2006-10-30 23:31:59Z minchau $
21 package org.apache.xpath.axes;
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;
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
38 public class OneStepIterator extends ChildTestIterator
40 static final long serialVersionUID = 4623710779664998283L;
41 /** The traversal axis from where the nodes will be filtered. */
42 protected int m_axis = -1;
44 /** The DTM inner traversal class, that corresponds to the super axis. */
45 protected DTMAxisIterator m_iterator;
48 * Create a OneStepIterator object.
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.
54 * @throws javax.xml.transform.TransformerException
56 OneStepIterator(Compiler compiler, int opPos, int analysis)
57 throws javax.xml.transform.TransformerException
59 super(compiler, opPos, analysis);
60 int firstStepPos = OpMap.getFirstChildPos(opPos);
62 m_axis = WalkerFactory.getAxisFromStep(compiler, firstStepPos);
68 * Create a OneStepIterator object.
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.
73 * @throws javax.xml.transform.TransformerException
75 public OneStepIterator(DTMAxisIterator iterator, int axis)
76 throws javax.xml.transform.TransformerException
80 m_iterator = iterator;
82 int whatToShow = DTMFilter.SHOW_ALL;
83 initNodeTest(whatToShow);
87 * Initialize the context values for this expression
90 * @param context The XPath runtime context for this
93 public void setRoot(int context, Object environment)
95 super.setRoot(context, environment);
97 m_iterator = m_cdtm.getAxisIterator(m_axis);
98 m_iterator.setStartNode(m_context);
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.
115 // Always call the superclass detach last!
121 * Get the next node via getFirstAttribute && getNextAttribute.
123 protected int getNextNode()
125 return m_lastFetched = m_iterator.next();
129 * Get a cloned iterator.
131 * @return A new iterator that can be used without mutating this one.
133 * @throws CloneNotSupportedException
135 public Object clone() throws CloneNotSupportedException
137 // Do not access the location path itterator during this operation!
139 OneStepIterator clone = (OneStepIterator) super.clone();
141 if(m_iterator != null)
143 clone.m_iterator = m_iterator.cloneIterator();
149 * Get a cloned Iterator that is reset to the beginning
152 * @return A cloned NodeIterator set of the start of the query.
154 * @throws CloneNotSupportedException
156 public DTMIterator cloneWithReset() throws CloneNotSupportedException
159 OneStepIterator clone = (OneStepIterator) super.cloneWithReset();
160 clone.m_iterator = m_iterator;
168 * Tells if this is a reverse axes. Overrides AxesWalker#isReverseAxes.
170 * @return true for this class.
172 public boolean isReverseAxes()
174 return m_iterator.isReverse();
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.
184 * @param predicateIndex The predicate index of the proximity position.
186 * @return The pridicate index, or -1.
188 protected int getProximityPosition(int predicateIndex)
191 return super.getProximityPosition(predicateIndex);
193 // A negative predicate index seems to occur with
194 // (preceding-sibling::*|following-sibling::*)/ancestor::*[position()]/*[position()]
196 if(predicateIndex < 0)
199 if (m_proximityPositions[predicateIndex] <= 0)
201 XPathContext xctxt = getXPathContext();
204 OneStepIterator clone = (OneStepIterator) this.clone();
206 int root = getRoot();
207 xctxt.pushCurrentNode(root);
208 clone.setRoot(root, xctxt);
210 // clone.setPredicateCount(predicateIndex);
211 clone.m_predCount = predicateIndex;
217 while (DTM.NULL != (next = clone.nextNode()))
222 m_proximityPositions[predicateIndex] += count;
224 catch (CloneNotSupportedException cnse)
231 xctxt.popCurrentNode();
235 return m_proximityPositions[predicateIndex];
239 * The number of nodes in the list. The range of valid child node indices
240 * is 0 to <code>length-1</code> inclusive.
242 * @return The number of nodes in the list, always greater or equal to zero.
244 public int getLength()
247 return super.getLength();
249 // Tell if this is being called from within a predicate.
250 boolean isPredicateTest = (this == m_execContext.getSubContextList());
252 // And get how many total predicates are part of this step.
253 int predCount = getPredicateCount();
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)
263 XPathContext xctxt = getXPathContext();
266 OneStepIterator clone = (OneStepIterator) this.cloneWithReset();
268 int root = getRoot();
269 xctxt.pushCurrentNode(root);
270 clone.setRoot(root, xctxt);
272 clone.m_predCount = m_predicateIndex;
276 while (DTM.NULL != (next = clone.nextNode()))
281 catch (CloneNotSupportedException cnse)
287 xctxt.popCurrentNode();
289 if (isPredicateTest && m_predicateIndex < 1)
296 * Count backwards one proximity position.
298 * @param i The predicate index.
300 protected void countProximityPosition(int i)
303 super.countProximityPosition(i);
304 else if (i < m_proximityPositions.length)
305 m_proximityPositions[i]--;
309 * Reset the iterator.
315 if(null != m_iterator)
320 * Returns the axis being iterated, if it is known.
322 * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
331 * @see Expression#deepEquals(Expression)
333 public boolean deepEquals(Expression expr)
335 if(!super.deepEquals(expr))
338 if(m_axis != ((OneStepIterator)expr).m_axis)