001: package net.sf.saxon.expr;
002:
003: import net.sf.saxon.om.Item;
004: import net.sf.saxon.om.NodeInfo;
005: import net.sf.saxon.om.SequenceIterator;
006: import net.sf.saxon.sort.NodeOrderComparer;
007: import net.sf.saxon.trans.XPathException;
008:
009: /**
010: * An enumeration representing a nodeset that is teh difference of two other NodeSets.
011: * There is an "except" operator in XPath 2.0 to create such an expression.
012: */
013:
014: public class DifferenceEnumeration implements SequenceIterator {
015:
016: private SequenceIterator p1;
017: private SequenceIterator p2;
018:
019: private NodeInfo nextNode1 = null;
020: private NodeInfo nextNode2 = null;
021: private NodeOrderComparer comparer;
022:
023: //private NodeInfo nextNode = null;
024: private NodeInfo current = null;
025: private int position = 0;
026:
027: /**
028: * Form an enumeration of the difference of two nodesets, that is, the nodes
029: * that are in p1 and that are not in p2.
030: * @param p1 the first operand
031: * @param p2 the second operand
032: * @param comparer the comparer
033: */
034:
035: public DifferenceEnumeration(SequenceIterator p1,
036: SequenceIterator p2, NodeOrderComparer comparer)
037: throws XPathException {
038: this .p1 = p1;
039: this .p2 = p2;
040: this .comparer = comparer;
041:
042: // move to the first node in each input nodeset
043:
044: nextNode1 = next(p1);
045: nextNode2 = next(p2);
046: }
047:
048: /**
049: * Get the next item from one of the input sequences,
050: * checking that it is a node.
051: */
052:
053: private NodeInfo next(SequenceIterator iter) throws XPathException {
054: return (NodeInfo) iter.next();
055: // rely on type-checking to prevent a ClassCastException
056: }
057:
058: public Item next() throws XPathException {
059: // main merge loop: if the node in p1 has a lower key value that that in p2, return it;
060: // if they are equal, advance both nodesets; if p1 is higher, advance p2.
061:
062: while (true) {
063:
064: if (nextNode1 == null) {
065: current = null;
066: position = -1;
067: return null;
068: }
069:
070: if (nextNode2 == null) {
071: // second node-set is exhausted; return the next node from the first node-set
072: return deliver();
073: }
074:
075: int c = comparer.compare(nextNode1, nextNode2);
076: if (c < 0) { // p1 is lower
077: return deliver();
078:
079: } else if (c > 0) { // p1 is higher
080: nextNode2 = next(p2);
081: if (nextNode2 == null) {
082: return deliver();
083: }
084:
085: } else { // keys are equal
086: nextNode2 = next(p2);
087: nextNode1 = next(p1);
088: }
089: }
090: }
091:
092: /**
093: * Deliver the next node from the first node-set, advancing the iterator to
094: * look-ahead for the next item, and setting the current and position variables.
095: * @return the next node from the first node-set
096: * @throws XPathException
097: */
098: private NodeInfo deliver() throws XPathException {
099: current = nextNode1;
100: nextNode1 = next(p1);
101: position++;
102: return current;
103: }
104:
105: public Item current() {
106: return current;
107: }
108:
109: public int position() {
110: return position;
111: }
112:
113: public SequenceIterator getAnother() throws XPathException {
114: return new DifferenceEnumeration(p1.getAnother(), p2
115: .getAnother(), comparer);
116: }
117:
118: /**
119: * Get properties of this iterator, as a bit-significant integer.
120: *
121: * @return the properties of this iterator. This will be some combination of
122: * properties such as {@link GROUNDED}, {@link LAST_POSITION_FINDER},
123: * and {@link LOOKAHEAD}. It is always
124: * acceptable to return the value zero, indicating that there are no known special properties.
125: * It is acceptable for the properties of the iterator to change depending on its state.
126: */
127:
128: public int getProperties() {
129: return 0;
130: }
131: }
132:
133: //
134: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
135: // you may not use this file except in compliance with the License. You may obtain a copy of the
136: // License at http://www.mozilla.org/MPL/
137: //
138: // Software distributed under the License is distributed on an "AS IS" basis,
139: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
140: // See the License for the specific language governing rights and limitations under the License.
141: //
142: // The Original Code is: all this file.
143: //
144: // The Initial Developer of the Original Code is Michael H. Kay.
145: //
146: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
147: //
148: // Contributor(s): none.
149: //
|