001: package net.sf.saxon.tinytree;
002:
003: import net.sf.saxon.om.AxisIteratorImpl;
004: import net.sf.saxon.om.Item;
005: import net.sf.saxon.om.SequenceIterator;
006: import net.sf.saxon.om.LookaheadIterator;
007: import net.sf.saxon.pattern.NodeTest;
008: import net.sf.saxon.style.StandardNames;
009: import net.sf.saxon.type.Type;
010:
011: /**
012: * This class supports both the child:: and following-sibling:: axes, which are
013: * identical except for the route to the first candidate node.
014: * It enumerates either the children or the following siblings of the specified node.
015: * In the case of children, the specified node must always
016: * be a node that has children: to ensure this, construct the enumeration
017: * using NodeInfo#getEnumeration()
018: */
019:
020: final class SiblingEnumeration extends AxisIteratorImpl implements
021: LookaheadIterator {
022:
023: private TinyTree tree;
024: private int nextNodeNr;
025: private NodeTest test;
026: private TinyNodeImpl startNode;
027: private TinyNodeImpl parentNode;
028: private boolean getChildren;
029: private boolean needToAdvance = false;
030:
031: /**
032: * Return an enumeration over children or siblings of the context node
033: * @param tree The TinyTree containing the context node
034: * @param node The context node, the start point for the iteration
035: * @param nodeTest Test that the selected nodes must satisfy, or null indicating
036: * that all nodes are selected
037: * @param getChildren True if children of the context node are to be returned, false
038: * if following siblings are required
039: */
040:
041: SiblingEnumeration(TinyTree tree, TinyNodeImpl node,
042: NodeTest nodeTest, boolean getChildren) {
043: this .tree = tree;
044: test = nodeTest;
045: startNode = node;
046: this .getChildren = getChildren;
047: if (getChildren) { // child:: axis
048: parentNode = node;
049: // move to first child
050: // ASSERT: we don't invoke this code unless the node has children
051: nextNodeNr = node.nodeNr + 1;
052:
053: } else { // following-sibling:: axis
054: parentNode = (TinyNodeImpl) node.getParent();
055: if (parentNode == null) {
056: nextNodeNr = -1;
057: } else {
058: // move to next sibling
059: nextNodeNr = tree.next[node.nodeNr];
060: while (tree.nodeKind[nextNodeNr] == Type.PARENT_POINTER) {
061: // skip dummy nodes
062: nextNodeNr = tree.next[nextNodeNr];
063: }
064: if (nextNodeNr < node.nodeNr) {
065: // if "next" pointer goes backwards, it's really an owner pointer from the last sibling
066: nextNodeNr = -1;
067: }
068: }
069: }
070:
071: // check if this matches the conditions
072: if (nextNodeNr >= 0 && nodeTest != null) {
073: if (!nodeTest.matches(this .tree, nextNodeNr)) {
074: needToAdvance = true;
075: }
076: }
077: }
078:
079: public Item next() {
080: // if needToAdvance == false, we are already on the correct node.
081: if (needToAdvance) {
082: final int this Node = nextNodeNr;
083: if (test == null) {
084: do {
085: nextNodeNr = tree.next[nextNodeNr];
086: } while (tree.nodeKind[nextNodeNr] == Type.PARENT_POINTER);
087: } else {
088: do {
089: nextNodeNr = tree.next[nextNodeNr];
090: } while (nextNodeNr >= this Node
091: && !test.matches(tree, nextNodeNr));
092: }
093:
094: if (nextNodeNr < this Node) { // indicates we've got to the last sibling
095: nextNodeNr = -1;
096: needToAdvance = false;
097: current = null;
098: position = -1;
099: return null;
100: }
101: }
102:
103: if (nextNodeNr == -1) {
104: return null;
105: }
106: needToAdvance = true;
107: position++;
108:
109: // if the caller only wants the atomized value, get it directly
110: // in the case where it's an untyped atomic value
111:
112: if (isAtomizing()
113: && tree.getTypeAnnotation(nextNodeNr) == StandardNames.XDT_UNTYPED) {
114: current = tree.getUntypedAtomicValue(nextNodeNr);
115: return current;
116: } else {
117: current = tree.getNode(nextNodeNr);
118: ((TinyNodeImpl) current).setParentNode(parentNode);
119: return current;
120: }
121: }
122:
123: /**
124: * Test whether there are any more nodes to come. This method is used only when testing whether the
125: * current item is the last in the sequence. It's not especially efficient, but is more efficient than
126: * the alternative strategy which involves counting how many nodes there are in the sequence.
127: * @return true if there are more items in the sequence
128: */
129:
130: public boolean hasNext() {
131: int n = nextNodeNr;
132: if (needToAdvance) {
133: if (test == null) {
134: do {
135: n = tree.next[n];
136: } while (tree.nodeKind[n] == Type.PARENT_POINTER);
137: } else {
138: do {
139: n = tree.next[n];
140: } while (n >= nextNodeNr && !test.matches(tree, n));
141: }
142:
143: if (n < nextNodeNr) { // indicates we've got to the last sibling
144: return false;
145: }
146: }
147:
148: return (n != -1);
149: }
150:
151: /**
152: * Get another enumeration of the same nodes
153: */
154:
155: public SequenceIterator getAnother() {
156: return new SiblingEnumeration(tree, startNode, test,
157: getChildren);
158: }
159:
160: public int getProperties() {
161: return LOOKAHEAD;
162: }
163:
164: }
165:
166: //
167: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
168: // you may not use this file except in compliance with the License. You may obtain a copy of the
169: // License at http://www.mozilla.org/MPL/
170: //
171: // Software distributed under the License is distributed on an "AS IS" basis,
172: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
173: // See the License for the specific language governing rights and limitations under the License.
174: //
175: // The Original Code is: all this file.
176: //
177: // The Initial Developer of the Original Code is Michael H. Kay.
178: //
179: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
180: //
181: // Contributor(s): none.
182: //
|