001: /*
002: * Copyright 1999-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: /*
017: * $Id: ReverseAxesWalker.java,v 1.15 2004/08/17 19:25:34 jycli Exp $
018: */
019: package org.apache.xpath.axes;
020:
021: import org.apache.xml.dtm.DTM;
022: import org.apache.xml.dtm.DTMAxisIterator;
023: import org.apache.xpath.XPathContext;
024:
025: /**
026: * Walker for a reverse axes.
027: * @see <a href="http://www.w3.org/TR/xpath#predicates">XPath 2.4 Predicates</a>
028: */
029: public class ReverseAxesWalker extends AxesWalker {
030: static final long serialVersionUID = 2847007647832768941L;
031:
032: /**
033: * Construct an AxesWalker using a LocPathIterator.
034: *
035: * @param locPathIterator The location path iterator that 'owns' this walker.
036: */
037: ReverseAxesWalker(LocPathIterator locPathIterator, int axis) {
038: super (locPathIterator, axis);
039: }
040:
041: /**
042: * Set the root node of the TreeWalker.
043: * (Not part of the DOM2 TreeWalker interface).
044: *
045: * @param root The context node of this step.
046: */
047: public void setRoot(int root) {
048: super .setRoot(root);
049: m_iterator = getDTM(root).getAxisIterator(m_axis);
050: m_iterator.setStartNode(root);
051: }
052:
053: /**
054: * Detaches the walker from the set which it iterated over, releasing
055: * any computational resources and placing the iterator in the INVALID
056: * state.
057: */
058: public void detach() {
059: m_iterator = null;
060: super .detach();
061: }
062:
063: /**
064: * Get the next node in document order on the axes.
065: *
066: * @return the next node in document order on the axes, or null.
067: */
068: protected int getNextNode() {
069: if (m_foundLast)
070: return DTM.NULL;
071:
072: int next = m_iterator.next();
073:
074: if (m_isFresh)
075: m_isFresh = false;
076:
077: if (DTM.NULL == next)
078: this .m_foundLast = true;
079:
080: return next;
081: }
082:
083: /**
084: * Tells if this is a reverse axes. Overrides AxesWalker#isReverseAxes.
085: *
086: * @return true for this class.
087: */
088: public boolean isReverseAxes() {
089: return true;
090: }
091:
092: // /**
093: // * Set the root node of the TreeWalker.
094: // *
095: // * @param root The context node of this step.
096: // */
097: // public void setRoot(int root)
098: // {
099: // super.setRoot(root);
100: // }
101:
102: /**
103: * Get the current sub-context position. In order to do the
104: * reverse axes count, for the moment this re-searches the axes
105: * up to the predicate. An optimization on this is to cache
106: * the nodes searched, but, for the moment, this case is probably
107: * rare enough that the added complexity isn't worth it.
108: *
109: * @param predicateIndex The predicate index of the proximity position.
110: *
111: * @return The pridicate index, or -1.
112: */
113: protected int getProximityPosition(int predicateIndex) {
114: // A negative predicate index seems to occur with
115: // (preceding-sibling::*|following-sibling::*)/ancestor::*[position()]/*[position()]
116: // -sb
117: if (predicateIndex < 0)
118: return -1;
119:
120: int count = m_proximityPositions[predicateIndex];
121:
122: if (count <= 0) {
123: AxesWalker savedWalker = wi().getLastUsedWalker();
124:
125: try {
126: ReverseAxesWalker clone = (ReverseAxesWalker) this
127: .clone();
128:
129: clone.setRoot(this .getRoot());
130:
131: clone.setPredicateCount(predicateIndex);
132:
133: clone.setPrevWalker(null);
134: clone.setNextWalker(null);
135: wi().setLastUsedWalker(clone);
136:
137: // Count 'em all
138: count++;
139: int next;
140:
141: while (DTM.NULL != (next = clone.nextNode())) {
142: count++;
143: }
144:
145: m_proximityPositions[predicateIndex] = count;
146: } catch (CloneNotSupportedException cnse) {
147:
148: // can't happen
149: } finally {
150: wi().setLastUsedWalker(savedWalker);
151: }
152: }
153:
154: return count;
155: }
156:
157: /**
158: * Count backwards one proximity position.
159: *
160: * @param i The predicate index.
161: */
162: protected void countProximityPosition(int i) {
163: if (i < m_proximityPositions.length)
164: m_proximityPositions[i]--;
165: }
166:
167: /**
168: * Get the number of nodes in this node list. The function is probably ill
169: * named?
170: *
171: *
172: * @param xctxt The XPath runtime context.
173: *
174: * @return the number of nodes in this node list.
175: */
176: public int getLastPos(XPathContext xctxt) {
177:
178: int count = 0;
179: AxesWalker savedWalker = wi().getLastUsedWalker();
180:
181: try {
182: ReverseAxesWalker clone = (ReverseAxesWalker) this .clone();
183:
184: clone.setRoot(this .getRoot());
185:
186: clone.setPredicateCount(this .getPredicateCount() - 1);
187:
188: clone.setPrevWalker(null);
189: clone.setNextWalker(null);
190: wi().setLastUsedWalker(clone);
191:
192: // Count 'em all
193: // count = 1;
194: int next;
195:
196: while (DTM.NULL != (next = clone.nextNode())) {
197: count++;
198: }
199: } catch (CloneNotSupportedException cnse) {
200:
201: // can't happen
202: } finally {
203: wi().setLastUsedWalker(savedWalker);
204: }
205:
206: return count;
207: }
208:
209: /**
210: * Returns true if all the nodes in the iteration well be returned in document
211: * order.
212: * Warning: This can only be called after setRoot has been called!
213: *
214: * @return false.
215: */
216: public boolean isDocOrdered() {
217: return false; // I think.
218: }
219:
220: /** The DTM inner traversal class, that corresponds to the super axis. */
221: protected DTMAxisIterator m_iterator;
222: }
|