001: package net.sf.saxon.sort;
002:
003: import net.sf.saxon.expr.Expression;
004: import net.sf.saxon.expr.XPathContext;
005: import net.sf.saxon.om.Item;
006: import net.sf.saxon.om.ListIterator;
007: import net.sf.saxon.om.LookaheadIterator;
008: import net.sf.saxon.om.SequenceIterator;
009: import net.sf.saxon.trans.DynamicError;
010: import net.sf.saxon.trans.XPathException;
011: import net.sf.saxon.value.AtomicValue;
012:
013: import java.util.ArrayList;
014: import java.util.Comparator;
015: import java.util.List;
016:
017: /**
018: * A GroupAdjacentIterator iterates over a sequence of groups defined by
019: * xsl:for-each-group group-adjacent="x". The groups are returned in
020: * order of first appearance.
021: */
022:
023: public class GroupAdjacentIterator implements GroupIterator,
024: LookaheadIterator {
025:
026: private SequenceIterator population;
027: private Expression keyExpression;
028: private Comparator collator;
029: private AtomicSortComparer comparer;
030: private AtomicSortComparer.ComparisonKey currentComparisonKey;
031: private XPathContext baseContext;
032: private XPathContext runningContext;
033: private AtomicValue currentKey = null;
034: private List currentMembers;
035: private AtomicValue nextKey = null;
036: private Item next;
037: private Item current = null;
038: private int position = 0;
039:
040: public GroupAdjacentIterator(SequenceIterator population,
041: Expression keyExpression, XPathContext baseContext,
042: Comparator collator) throws XPathException {
043: this .population = population;
044: this .keyExpression = keyExpression;
045: this .baseContext = baseContext;
046: this .runningContext = baseContext.newMinorContext();
047: //runningContext.setOrigin(baseContext);
048: runningContext.setCurrentIterator(population);
049: this .collator = collator;
050: this .comparer = new AtomicSortComparer(collator, baseContext);
051: next = population.next();
052: if (next != null) {
053: nextKey = (AtomicValue) keyExpression
054: .evaluateItem(runningContext);
055: }
056: }
057:
058: private void advance() throws XPathException {
059: currentMembers = new ArrayList(20);
060: currentMembers.add(current);
061: while (true) {
062: Item nextCandidate = population.next();
063: if (nextCandidate == null) {
064: break;
065: }
066: AtomicValue candidateKey = (AtomicValue) keyExpression
067: .evaluateItem(runningContext);
068: try {
069: if (currentComparisonKey.equals(comparer
070: .getComparisonKey(candidateKey))) {
071: currentMembers.add(nextCandidate);
072: } else {
073: next = nextCandidate;
074: nextKey = candidateKey;
075: return;
076: }
077: } catch (ClassCastException e) {
078: DynamicError err = new DynamicError(
079: "Grouping key values are of non-comparable types ("
080: + currentKey.getItemType(null)
081: + " and "
082: + candidateKey.getItemType(null) + ')');
083: err.setIsTypeError(true);
084: err.setXPathContext(runningContext);
085: throw err;
086: }
087: }
088: next = null;
089: nextKey = null;
090: }
091:
092: public AtomicValue getCurrentGroupingKey() {
093: return currentKey;
094: }
095:
096: public SequenceIterator iterateCurrentGroup() {
097: return new ListIterator(currentMembers);
098: }
099:
100: public boolean hasNext() {
101: return next != null;
102: }
103:
104: public Item next() throws XPathException {
105: if (next == null) {
106: current = null;
107: position = -1;
108: return null;
109: }
110: current = next;
111: currentKey = nextKey;
112: currentComparisonKey = comparer.getComparisonKey(currentKey);
113: position++;
114: advance();
115: return current;
116: }
117:
118: public Item current() {
119: return current;
120: }
121:
122: public int position() {
123: return position;
124: }
125:
126: public SequenceIterator getAnother() throws XPathException {
127: return new GroupAdjacentIterator(population.getAnother(),
128: keyExpression, baseContext, collator);
129: }
130:
131: /**
132: * Get properties of this iterator, as a bit-significant integer.
133: *
134: * @return the properties of this iterator. This will be some combination of
135: * properties such as {@link GROUNDED}, {@link LAST_POSITION_FINDER},
136: * and {@link LOOKAHEAD}. It is always
137: * acceptable to return the value zero, indicating that there are no known special properties.
138: * It is acceptable for the properties of the iterator to change depending on its state.
139: */
140:
141: public int getProperties() {
142: return LOOKAHEAD;
143: }
144:
145: }
146:
147: //
148: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
149: // you may not use this file except in compliance with the License. You may obtain a copy of the
150: // License at http://www.mozilla.org/MPL/
151: //
152: // Software distributed under the License is distributed on an "AS IS" basis,
153: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
154: // See the License for the specific language governing rights and limitations under the License.
155: //
156: // The Original Code is: all this file.
157: //
158: // The Initial Developer of the Original Code is Michael H. Kay
159: //
160: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
161: //
162: // Contributor(s): none
163: //
|