001: package net.sf.saxon.om;
002:
003: import net.sf.saxon.expr.LastPositionFinder;
004: import net.sf.saxon.expr.ReversibleIterator;
005: import net.sf.saxon.value.SingletonNode;
006: import net.sf.saxon.value.Value;
007: import net.sf.saxon.value.UntypedAtomicValue;
008: import net.sf.saxon.value.StringValue;
009: import net.sf.saxon.trans.XPathException;
010: import net.sf.saxon.type.Type;
011: import net.sf.saxon.style.StandardNames;
012:
013: /**
014: * SingletonIterator: an iterator over a sequence of zero or one values
015: */
016:
017: public class SingletonIterator implements AxisIterator,
018: ReversibleIterator, LastPositionFinder, GroundedIterator,
019: LookaheadIterator, AtomizableIterator {
020:
021: private Item value;
022: private int position = 0;
023:
024: /**
025: * Private constructor: external classes should use the factory method
026: * @param value the item to iterate over
027: */
028:
029: private SingletonIterator(Item value) {
030: this .value = value;
031: }
032:
033: /**
034: * Factory method.
035: * @param item the item to iterate over
036: * @return a SingletonIterator over the supplied item, or an EmptyIterator
037: * if the supplied item is null.
038: */
039:
040: public static AxisIterator makeIterator(Item item) {
041: if (item == null) {
042: return EmptyIterator.getInstance();
043: } else {
044: return new SingletonIterator(item);
045: }
046: }
047:
048: /**
049: * Determine whether there are more items to come. Note that this operation
050: * is stateless and it is not necessary (or usual) to call it before calling
051: * next(). It is used only when there is an explicit need to tell if we
052: * are at the last element.
053: *
054: * @return true if there are more items
055: */
056:
057: public boolean hasNext() {
058: return position == 0;
059: }
060:
061: public Item next() {
062: if (position == 0) {
063: position = 1;
064: return value;
065: } else if (position == 1) {
066: position = -1;
067: return null;
068: } else {
069: return null;
070: }
071: }
072:
073: public Item current() {
074: if (position == 1) {
075: return value;
076: } else {
077: return null;
078: }
079: }
080:
081: /**
082: * Return the current position in the sequence.
083: * @return 0 before the first call on next(); 1 before the second call on next(); -1 after the second
084: * call on next().
085: */
086: public int position() {
087: return position;
088: }
089:
090: public int getLastPosition() {
091: return 1;
092: }
093:
094: public SequenceIterator getAnother() {
095: return new SingletonIterator(value);
096: }
097:
098: public SequenceIterator getReverseIterator() {
099: return new SingletonIterator(value);
100: }
101:
102: public Item getValue() {
103: return value;
104: }
105:
106: /**
107: * Return a SequenceExtent containing all the items in the sequence returned by this
108: * SequenceIterator
109: *
110: * @return the corresponding SequenceExtent if it exists, or null if it doesn't; in this case
111: * the caller must construct a new SequenceExtent by calling new SequenceExtent(iter.getAnother())
112: */
113:
114: public Value materialize() {
115: if (value instanceof Value) {
116: try {
117: value = (Item) ((Value) value).reduce();
118: } catch (XPathException err) {
119: }
120: return (Value) value;
121: } else {
122: return new SingletonNode((NodeInfo) value);
123: }
124: }
125:
126: /**
127: * Indicate that any nodes returned in the sequence will be atomized. This
128: * means that if it wishes to do so, the implementation can return the typed
129: * values of the nodes rather than the nodes themselves. The implementation
130: * is free to ignore this hint.
131: * <p>
132: * This implementation attempts atomization of a singleton node if it is untyped.
133: * This avoids adding an iterator to iterate over the value in the common case where
134: * the typed value of the node is a single atomic value.
135: *
136: * @param atomizing true if the caller of this iterator will atomize any
137: * nodes that are returned, and is therefore willing to accept the typed
138: * value of the nodes instead of the nodes themselves.
139: */
140:
141: public void setIsAtomizing(boolean atomizing) {
142: if (atomizing && (value instanceof NodeInfo)) {
143: NodeInfo node = (NodeInfo) value;
144: switch (node.getNodeKind()) {
145: case Type.DOCUMENT:
146: case Type.TEXT:
147: value = new UntypedAtomicValue(node.getStringValueCS());
148: return;
149:
150: case Type.ELEMENT:
151: case Type.ATTRIBUTE:
152: int t = ((NodeInfo) value).getTypeAnnotation();
153: if (t == -1 || t == StandardNames.XDT_UNTYPED
154: || t == StandardNames.XDT_UNTYPED_ATOMIC) {
155: value = new UntypedAtomicValue(node
156: .getStringValueCS());
157: return;
158: } else {
159: // do nothing: don't attempt to atomize the node here
160: return;
161: }
162:
163: case Type.COMMENT:
164: case Type.PROCESSING_INSTRUCTION:
165: case Type.NAMESPACE:
166: value = new StringValue(node.getStringValueCS());
167: return;
168: default:
169: return;
170: }
171: }
172: }
173:
174: /**
175: * Get properties of this iterator, as a bit-significant integer.
176: *
177: * @return the properties of this iterator. This will be some combination of
178: * properties such as {@link GROUNDED}, {@link LAST_POSITION_FINDER},
179: * and {@link LOOKAHEAD}. It is always
180: * acceptable to return the value zero, indicating that there are no known special properties.
181: * It is acceptable for the properties of the iterator to change depending on its state.
182: */
183:
184: public int getProperties() {
185: return GROUNDED | LAST_POSITION_FINDER | LOOKAHEAD | ATOMIZABLE;
186: }
187:
188: }
189:
190: //
191: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
192: // you may not use this file except in compliance with the License. You may obtain a copy of the
193: // License at http://www.mozilla.org/MPL/
194: //
195: // Software distributed under the License is distributed on an "AS IS" basis,
196: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
197: // See the License for the specific language governing rights and limitations under the License.
198: //
199: // The Original Code is: all this file.
200: //
201: // The Initial Developer of the Original Code is Michael H. Kay.
202: //
203: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
204: //
205: // Contributor(s): none.
206: //
|