001: package net.sf.saxon.expr;
002:
003: import net.sf.saxon.om.AtomizableIterator;
004: import net.sf.saxon.om.Item;
005: import net.sf.saxon.om.SequenceIterator;
006: import net.sf.saxon.trans.XPathException;
007:
008: /**
009: * MappingIterator merges a sequence of sequences into a single flat
010: * sequence. It takes as inputs an iteration, and a mapping function to be
011: * applied to each Item returned by that iteration. The mapping function itself
012: * returns another iteration. The result is an iteration of the concatenation of all
013: * the iterations returned by the mapping function.<p>
014: *
015: * This is a powerful class. It is used, with different mapping functions,
016: * in a great variety of ways. It underpins the way that "for" expressions and
017: * path expressions are evaluated, as well as sequence expressions. It is also
018: * used in the implementation of the document(), key(), and id() functions.
019: */
020:
021: public final class MappingIterator implements SequenceIterator,
022: AtomizableIterator {
023:
024: private SequenceIterator base;
025: private MappingFunction action;
026: private XPathContext context;
027: //private Object info;
028: private SequenceIterator results = null;
029: private boolean atomizing = false;
030: private Item current = null;
031: private int position = 0;
032:
033: /**
034: * Construct a MappingIterator that will apply a specified MappingFunction to
035: * each Item returned by the base iterator.
036: * @param base the base iterator
037: * @param action the mapping function to be applied
038: * @param context the processing context. This should be supplied only if each item to be processed
039: * is to become the context item. In this case "base" should be the same as context.getCurrentIterator().
040: */
041:
042: public MappingIterator(SequenceIterator base,
043: MappingFunction action, XPathContext context) {
044: // System.err.println("New Mapping iterator " + this + " with base " + base);
045: this .base = base;
046: this .action = action;
047: this .context = context;
048: }
049:
050: public Item next() throws XPathException {
051: Item nextItem;
052: while (true) {
053: if (results != null) {
054: nextItem = results.next();
055: if (nextItem != null) {
056: break;
057: } else {
058: results = null;
059: }
060: }
061: Item nextSource = base.next();
062: if (nextSource != null) {
063: // Call the supplied mapping function
064: Object obj = action.map(nextSource, context);
065:
066: // The result may be null (representing an empty sequence), an item
067: // (representing a singleton sequence), or a SequenceIterator (any sequence)
068:
069: if (obj != null) {
070: if (obj instanceof Item) {
071: nextItem = (Item) obj;
072: results = null;
073: break;
074: }
075: results = (SequenceIterator) obj;
076: if (atomizing
077: && results instanceof AtomizableIterator) {
078: ((AtomizableIterator) results)
079: .setIsAtomizing(atomizing);
080: }
081: nextItem = results.next();
082: if (nextItem == null) {
083: results = null;
084: } else {
085: break;
086: }
087: }
088: // now go round the loop to get the next item from the base sequence
089: } else {
090: results = null;
091: current = null;
092: position = -1;
093: return null;
094: }
095: }
096:
097: current = nextItem;
098: // System.err.println("MappingIterator.next(), this = " + this + " returning " + ((net.sf.saxon.om.NodeInfo)current).generateId() );
099: position++;
100: return nextItem;
101: }
102:
103: public Item current() {
104: return current;
105: }
106:
107: public int position() {
108: return position;
109: }
110:
111: public SequenceIterator getAnother() throws XPathException {
112: // System.err.println(this + " getAnother() ");
113: SequenceIterator newBase = base.getAnother();
114: XPathContext c = context;
115: if (c != null) {
116: c = c.newMinorContext();
117: c.setCurrentIterator(newBase);
118: c.setOrigin(context.getOrigin());
119: }
120: MappingIterator m = new MappingIterator(newBase, action, c);
121: m.setIsAtomizing(atomizing);
122: return m;
123: }
124:
125: /**
126: * Get properties of this iterator, as a bit-significant integer.
127: *
128: * @return the properties of this iterator. This will be some combination of
129: * properties such as {@link GROUNDED}, {@link LAST_POSITION_FINDER},
130: * and {@link LOOKAHEAD}. It is always
131: * acceptable to return the value zero, indicating that there are no known special properties.
132: * It is acceptable for the properties of the iterator to change depending on its state.
133: */
134:
135: public int getProperties() {
136: return ATOMIZABLE;
137: }
138:
139: /**
140: * Indicate that any nodes returned in the sequence will be atomized. This
141: * means that if it wishes to do so, the implementation can return the typed
142: * values of the nodes rather than the nodes themselves. The implementation
143: * is free to ignore this hint.
144: * @param atomizing true if the caller of this iterator will atomize any
145: * nodes that are returned, and is therefore willing to accept the typed
146: * value of the nodes instead of the nodes themselves.
147: */
148:
149: public void setIsAtomizing(boolean atomizing) {
150: this .atomizing = atomizing;
151: }
152:
153: }
154:
155: //
156: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
157: // you may not use this file except in compliance with the License. You may obtain a copy of the
158: // License at http://www.mozilla.org/MPL/
159: //
160: // Software distributed under the License is distributed on an "AS IS" basis,
161: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
162: // See the License for the specific language governing rights and limitations under the License.
163: //
164: // The Original Code is: all this file.
165: //
166: // The Initial Developer of the Original Code is Michael H. Kay
167: //
168: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
169: //
170: // Contributor(s): none.
171: //
|