View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 1999-2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  /*
21   * $Id: DTMAxisIteratorBase.java,v 1.2.4.1 2005/09/15 08:14:59 suresh_emailid Exp $
22   */
23  package com.sun.org.apache.xml.internal.dtm.ref;
24  
25  import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
26  
27  /**
28   * This class serves as a default base for implementations of mutable
29   * DTMAxisIterators.
30   */
31  public abstract class DTMAxisIteratorBase implements DTMAxisIterator
32  {
33  
34    /** The position of the last node within the iteration, as defined by XPath.
35     * Note that this is _not_ the node's handle within the DTM. Also, don't
36     * confuse it with the current (most recently returned) position.
37     */
38    protected int _last = -1;
39  
40    /** The position of the current node within the iteration, as defined by XPath.
41     * Note that this is _not_ the node's handle within the DTM!
42     */
43    protected int _position = 0;
44  
45    /** The position of the marked node within the iteration;
46     * a saved itaration state that we may want to come back to.
47     * Note that only one mark is maintained; there is no stack.
48     */
49    protected int _markedNode;
50  
51    /** The handle to the start, or root, of the iteration.
52     * Set this to END to construct an empty iterator.
53     */
54    protected int _startNode = DTMAxisIterator.END;
55  
56    /** True if the start node should be considered part of the iteration.
57     * False will cause it to be skipped.
58     */
59    protected boolean _includeSelf = false;
60  
61    /** True if this iteration can be restarted. False otherwise (eg, if
62     * we are iterating over a stream that can not be re-scanned, or if
63     * the iterator was produced by cloning another iterator.)
64     */
65    protected boolean _isRestartable = true;
66  
67    /**
68     * Get start to END should 'close' the iterator,
69     * i.e. subsequent call to next() should return END.
70     *
71     * @return The root node of the iteration.
72     */
73    public int getStartNode()
74    {
75      return _startNode;
76    }
77  
78    /**
79     * @return A DTMAxisIterator which has been reset to the start node,
80     * which may or may not be the same as this iterator.
81     * */
82    public DTMAxisIterator reset()
83    {
84  
85      final boolean temp = _isRestartable;
86  
87      _isRestartable = true;
88  
89      setStartNode(_startNode);
90  
91      _isRestartable = temp;
92  
93      return this;
94    }
95  
96    /**
97     * Set the flag to include the start node in the iteration.
98     *
99     *
100    * @return This default method returns just returns this DTMAxisIterator,
101    * after setting the flag.
102    * (Returning "this" permits C++-style chaining of
103    * method calls into a single expression.)
104    */
105   public DTMAxisIterator includeSelf()
106   {
107 
108     _includeSelf = true;
109 
110     return this;
111   }
112 
113   /** Returns the position of the last node within the iteration, as
114    * defined by XPath.  In a forward iterator, I believe this equals the number of nodes which this
115    * iterator will yield. In a reverse iterator, I believe it should return
116    * 1 (since the "last" is the first produced.)
117    *
118    * This may be an expensive operation when called the first time, since
119    * it may have to iterate through a large part of the document to produce
120    * its answer.
121    *
122    * @return The number of nodes in this iterator (forward) or 1 (reverse).
123    */
124   public int getLast()
125   {
126 
127     if (_last == -1)            // Not previously established
128     {
129       // Note that we're doing both setMark() -- which saves _currentChild
130       // -- and explicitly saving our position counter (number of nodes
131       // yielded so far).
132       //
133       // %REVIEW% Should position also be saved by setMark()?
134       // (It wasn't in the XSLTC version, but I don't understand why not.)
135 
136       final int temp = _position; // Save state
137       setMark();
138 
139       reset();                  // Count the nodes found by this iterator
140       do
141       {
142         _last++;
143       }
144       while (next() != END);
145 
146       gotoMark();               // Restore saved state
147       _position = temp;
148     }
149 
150     return _last;
151   }
152 
153   /**
154    * @return The position of the current node within the set, as defined by
155    * XPath. Note that this is one-based, not zero-based.
156    */
157   public int getPosition()
158   {
159     return _position == 0 ? 1 : _position;
160   }
161 
162   /**
163    * @return true if this iterator has a reversed axis, else false
164    */
165   public boolean isReverse()
166   {
167     return false;
168   }
169 
170   /**
171    * Returns a deep copy of this iterator. Cloned iterators may not be
172    * restartable. The iterator being cloned may or may not become
173    * non-restartable as a side effect of this operation.
174    *
175    * @return a deep copy of this iterator.
176    */
177   public DTMAxisIterator cloneIterator()
178   {
179 
180     try
181     {
182       final DTMAxisIteratorBase clone = (DTMAxisIteratorBase) super.clone();
183 
184       clone._isRestartable = false;
185 
186       // return clone.reset();
187       return clone;
188     }
189     catch (CloneNotSupportedException e)
190     {
191       throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(e);
192     }
193   }
194 
195   /**
196    * Do any final cleanup that is required before returning the node that was
197    * passed in, and then return it. The intended use is
198    * <br />
199    * <code>return returnNode(node);</code>
200    *
201    * %REVIEW% If we're calling it purely for side effects, should we really
202    * be bothering with a return value? Something like
203    * <br />
204    * <code> accept(node); return node; </code>
205    * <br />
206    * would probably optimize just about as well and avoid questions
207    * about whether what's returned could ever be different from what's
208    * passed in.
209    *
210    * @param node Node handle which iteration is about to yield.
211    *
212    * @return The node handle passed in.  */
213   protected final int returnNode(final int node)
214   {
215     _position++;
216 
217     return node;
218   }
219 
220   /**
221    * Reset the position to zero. NOTE that this does not change the iteration
222    * state, only the position number associated with that state.
223    *
224    * %REVIEW% Document when this would be used?
225    *
226    * @return This instance.
227    */
228   protected final DTMAxisIterator resetPosition()
229   {
230 
231     _position = 0;
232 
233     return this;
234   }
235 
236   /**
237    * Returns true if all the nodes in the iteration well be returned in document
238    * order.
239    *
240    * @return true as a default.
241    */
242   public boolean isDocOrdered()
243   {
244     return true;
245   }
246 
247   /**
248    * Returns the axis being iterated, if it is known.
249    *
250    * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
251    * types.
252    */
253   public int getAxis()
254   {
255     return -1;
256   }
257 
258   public void setRestartable(boolean isRestartable) {
259     _isRestartable = isRestartable;
260   }
261 
262   /**
263    * Return the node at the given position.
264    *
265    * @param position The position
266    * @return The node at the given position.
267    */
268   public int getNodeByPosition(int position)
269   {
270     if (position > 0) {
271       final int pos = isReverse() ? getLast() - position + 1
272                                    : position;
273       int node;
274       while ((node = next()) != DTMAxisIterator.END) {
275         if (pos == getPosition()) {
276           return node;
277         }
278       }
279     }
280     return END;
281   }
282 
283 }