001: /*
002: * Copyright 1999-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: /*
017: * $Id: DTMAxisIteratorBase.java,v 1.11 2004/02/16 23:06:11 minchau Exp $
018: */
019: package org.apache.xml.dtm.ref;
020:
021: import org.apache.xml.dtm.DTMAxisIterator;
022:
023: /**
024: * This class serves as a default base for implementations of mutable
025: * DTMAxisIterators.
026: */
027: public abstract class DTMAxisIteratorBase implements DTMAxisIterator {
028:
029: /** The position of the last node within the iteration, as defined by XPath.
030: * Note that this is _not_ the node's handle within the DTM. Also, don't
031: * confuse it with the current (most recently returned) position.
032: */
033: protected int _last = -1;
034:
035: /** The position of the current node within the iteration, as defined by XPath.
036: * Note that this is _not_ the node's handle within the DTM!
037: */
038: protected int _position = 0;
039:
040: /** The position of the marked node within the iteration;
041: * a saved itaration state that we may want to come back to.
042: * Note that only one mark is maintained; there is no stack.
043: */
044: protected int _markedNode;
045:
046: /** The handle to the start, or root, of the iteration.
047: * Set this to END to construct an empty iterator.
048: */
049: protected int _startNode = DTMAxisIterator.END;
050:
051: /** True if the start node should be considered part of the iteration.
052: * False will cause it to be skipped.
053: */
054: protected boolean _includeSelf = false;
055:
056: /** True if this iteration can be restarted. False otherwise (eg, if
057: * we are iterating over a stream that can not be re-scanned, or if
058: * the iterator was produced by cloning another iterator.)
059: */
060: protected boolean _isRestartable = true;
061:
062: /**
063: * Get start to END should 'close' the iterator,
064: * i.e. subsequent call to next() should return END.
065: *
066: * @return The root node of the iteration.
067: */
068: public int getStartNode() {
069: return _startNode;
070: }
071:
072: /**
073: * @return A DTMAxisIterator which has been reset to the start node,
074: * which may or may not be the same as this iterator.
075: * */
076: public DTMAxisIterator reset() {
077:
078: final boolean temp = _isRestartable;
079:
080: _isRestartable = true;
081:
082: setStartNode(_startNode);
083:
084: _isRestartable = temp;
085:
086: return this ;
087: }
088:
089: /**
090: * Set the flag to include the start node in the iteration.
091: *
092: *
093: * @return This default method returns just returns this DTMAxisIterator,
094: * after setting the flag.
095: * (Returning "this" permits C++-style chaining of
096: * method calls into a single expression.)
097: */
098: public DTMAxisIterator includeSelf() {
099:
100: _includeSelf = true;
101:
102: return this ;
103: }
104:
105: /** Returns the position of the last node within the iteration, as
106: * defined by XPath. In a forward iterator, I believe this equals the number of nodes which this
107: * iterator will yield. In a reverse iterator, I believe it should return
108: * 1 (since the "last" is the first produced.)
109: *
110: * This may be an expensive operation when called the first time, since
111: * it may have to iterate through a large part of the document to produce
112: * its answer.
113: *
114: * @return The number of nodes in this iterator (forward) or 1 (reverse).
115: */
116: public int getLast() {
117:
118: if (_last == -1) // Not previously established
119: {
120: // Note that we're doing both setMark() -- which saves _currentChild
121: // -- and explicitly saving our position counter (number of nodes
122: // yielded so far).
123: //
124: // %REVIEW% Should position also be saved by setMark()?
125: // (It wasn't in the XSLTC version, but I don't understand why not.)
126:
127: final int temp = _position; // Save state
128: setMark();
129:
130: reset(); // Count the nodes found by this iterator
131: do {
132: _last++;
133: } while (next() != END);
134:
135: gotoMark(); // Restore saved state
136: _position = temp;
137: }
138:
139: return _last;
140: }
141:
142: /**
143: * @return The position of the current node within the set, as defined by
144: * XPath. Note that this is one-based, not zero-based.
145: */
146: public int getPosition() {
147: return _position == 0 ? 1 : _position;
148: }
149:
150: /**
151: * @return true if this iterator has a reversed axis, else false
152: */
153: public boolean isReverse() {
154: return false;
155: }
156:
157: /**
158: * Returns a deep copy of this iterator. Cloned iterators may not be
159: * restartable. The iterator being cloned may or may not become
160: * non-restartable as a side effect of this operation.
161: *
162: * @return a deep copy of this iterator.
163: */
164: public DTMAxisIterator cloneIterator() {
165:
166: try {
167: final DTMAxisIteratorBase clone = (DTMAxisIteratorBase) super
168: .clone();
169:
170: clone._isRestartable = false;
171:
172: // return clone.reset();
173: return clone;
174: } catch (CloneNotSupportedException e) {
175: throw new org.apache.xml.utils.WrappedRuntimeException(e);
176: }
177: }
178:
179: /**
180: * Do any final cleanup that is required before returning the node that was
181: * passed in, and then return it. The intended use is
182: * <br />
183: * <code>return returnNode(node);</code>
184: *
185: * %REVIEW% If we're calling it purely for side effects, should we really
186: * be bothering with a return value? Something like
187: * <br />
188: * <code> accept(node); return node; </code>
189: * <br />
190: * would probably optimize just about as well and avoid questions
191: * about whether what's returned could ever be different from what's
192: * passed in.
193: *
194: * @param node Node handle which iteration is about to yield.
195: *
196: * @return The node handle passed in. */
197: protected final int returnNode(final int node) {
198: _position++;
199:
200: return node;
201: }
202:
203: /**
204: * Reset the position to zero. NOTE that this does not change the iteration
205: * state, only the position number associated with that state.
206: *
207: * %REVIEW% Document when this would be used?
208: *
209: * @return This instance.
210: */
211: protected final DTMAxisIterator resetPosition() {
212:
213: _position = 0;
214:
215: return this ;
216: }
217:
218: /**
219: * Returns true if all the nodes in the iteration well be returned in document
220: * order.
221: *
222: * @return true as a default.
223: */
224: public boolean isDocOrdered() {
225: return true;
226: }
227:
228: /**
229: * Returns the axis being iterated, if it is known.
230: *
231: * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
232: * types.
233: */
234: public int getAxis() {
235: return -1;
236: }
237:
238: public void setRestartable(boolean isRestartable) {
239: _isRestartable = isRestartable;
240: }
241:
242: /**
243: * Return the node at the given position.
244: *
245: * @param position The position
246: * @return The node at the given position.
247: */
248: public int getNodeByPosition(int position) {
249: if (position > 0) {
250: final int pos = isReverse() ? getLast() - position + 1
251: : position;
252: int node;
253: while ((node = next()) != DTMAxisIterator.END) {
254: if (pos == getPosition()) {
255: return node;
256: }
257: }
258: }
259: return END;
260: }
261:
262: }
|