001: package net.sf.saxon.functions;
002:
003: import net.sf.saxon.expr.XPathContext;
004: import net.sf.saxon.om.Item;
005: import net.sf.saxon.om.SequenceIterator;
006: import net.sf.saxon.sort.AtomicSortComparer;
007: import net.sf.saxon.trans.XPathException;
008: import net.sf.saxon.value.AtomicValue;
009:
010: import java.util.HashSet;
011:
012: /**
013: * The XPath 2.0 distinct-values() function
014: */
015:
016: public class DistinctValues extends CollatingFunction {
017:
018: /**
019: * Evaluate the function to return an iteration of selected values or nodes.
020: */
021:
022: public SequenceIterator iterate(XPathContext context)
023: throws XPathException {
024: SequenceIterator iter = argument[0].iterate(context);
025: return new DistinctIterator(iter, getAtomicSortComparer(1,
026: context));
027: }
028:
029: /**
030: * Get a AtomicSortComparer that can be used to compare values
031: * @param arg the position of the argument (starting at 0) containing the collation name.
032: * If this argument was not supplied, the default collation is used
033: * @param context The dynamic evaluation context.
034: */
035:
036: protected AtomicSortComparer getAtomicSortComparer(int arg,
037: XPathContext context) throws XPathException {
038: AtomicSortComparer asc = new AtomicSortComparer(getCollator(
039: arg, context), (context == null ? conversionContext
040: : context));
041: return asc;
042: }
043:
044: /**
045: * Iterator class to return the distinct values in a sequence
046: */
047:
048: public static class DistinctIterator implements SequenceIterator {
049:
050: private SequenceIterator base;
051: private AtomicSortComparer comparer;
052: private int position;
053: private AtomicValue current;
054: private HashSet lookup = new HashSet(40);
055:
056: /**
057: * Create an iterator over the distinct values in a sequence
058: * @param base the input sequence. This must return atomic values only.
059: * @param comparer The comparer used to obtain comparison keys from each value;
060: * these comparison keys are themselves compared using equals().
061: */
062:
063: public DistinctIterator(SequenceIterator base,
064: AtomicSortComparer comparer) {
065: this .base = base;
066: this .comparer = comparer;
067: position = 0;
068: }
069:
070: /**
071: * Get the next item in the sequence. <BR>
072: *
073: * @return the next item, or null if there are no more items.
074: * @throws net.sf.saxon.trans.XPathException
075: * if an error occurs retrieving the next item
076: */
077:
078: public Item next() throws XPathException {
079: while (true) {
080: AtomicValue nextBase = (AtomicValue) base.next();
081: if (nextBase == null) {
082: current = null;
083: position = -1;
084: return null;
085: }
086: AtomicSortComparer.ComparisonKey key = comparer
087: .getComparisonKey(nextBase);
088: if (lookup.contains(key)) {
089: continue;
090: } else {
091: lookup.add(key);
092: current = nextBase;
093: position++;
094: return nextBase;
095: }
096: }
097: }
098:
099: /**
100: * Get the current value in the sequence (the one returned by the
101: * most recent call on next()). This will be null before the first
102: * call of next().
103: *
104: * @return the current item, the one most recently returned by a call on
105: * next(); or null, if next() has not been called, or if the end
106: * of the sequence has been reached.
107: */
108:
109: public Item current() {
110: return current;
111: }
112:
113: /**
114: * Get the current position. This will be zero before the first call
115: * on next(), otherwise it will be the number of times that next() has
116: * been called.
117: *
118: * @return the current position, the position of the item returned by the
119: * most recent call of next()
120: */
121:
122: public int position() {
123: return position;
124: }
125:
126: /**
127: * Get another SequenceIterator that iterates over the same items as the original,
128: * but which is repositioned at the start of the sequence.
129: *
130: * @return a SequenceIterator that iterates over the same items,
131: * positioned before the first item
132: * @throws net.sf.saxon.trans.XPathException
133: * if any error occurs
134: */
135:
136: public SequenceIterator getAnother() throws XPathException {
137: return new DistinctIterator(base.getAnother(), comparer);
138: }
139:
140: /**
141: * Get properties of this iterator, as a bit-significant integer.
142: *
143: * @return the properties of this iterator. This will be some combination of
144: * properties such as {@link GROUNDED}, {@link LAST_POSITION_FINDER},
145: * and {@link LOOKAHEAD}. It is always
146: * acceptable to return the value zero, indicating that there are no known special properties.
147: * It is acceptable for the properties of the iterator to change depending on its state.
148: */
149:
150: public int getProperties() {
151: return 0;
152: }
153: }
154:
155: }
156:
157: //
158: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
159: // you may not use this file except in compliance with the License. You may obtain a copy of the
160: // License at http://www.mozilla.org/MPL/
161: //
162: // Software distributed under the License is distributed on an "AS IS" basis,
163: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
164: // See the License for the specific language governing rights and limitations under the License.
165: //
166: // The Original Code is: all this file.
167: //
168: // The Initial Developer of the Original Code is Michael H. Kay.
169: //
170: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
171: //
172: // Contributor(s): none.
173: //
|