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