1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 /* 19 * $Id: ReverseAxesWalker.java 513117 2007-03-01 03:28:52Z minchau $ 20 */ 21 package org.apache.xpath.axes; 22 23 import org.apache.xml.dtm.DTM; 24 import org.apache.xml.dtm.DTMAxisIterator; 25 import org.apache.xpath.XPathContext; 26 27 /** 28 * Walker for a reverse axes. 29 * @see <a href="http://www.w3.org/TR/xpath#predicates">XPath 2.4 Predicates</a> 30 */ 31 public class ReverseAxesWalker extends AxesWalker 32 { 33 static final long serialVersionUID = 2847007647832768941L; 34 35 /** 36 * Construct an AxesWalker using a LocPathIterator. 37 * 38 * @param locPathIterator The location path iterator that 'owns' this walker. 39 */ 40 ReverseAxesWalker(LocPathIterator locPathIterator, int axis) 41 { 42 super(locPathIterator, axis); 43 } 44 45 /** 46 * Set the root node of the TreeWalker. 47 * (Not part of the DOM2 TreeWalker interface). 48 * 49 * @param root The context node of this step. 50 */ 51 public void setRoot(int root) 52 { 53 super.setRoot(root); 54 m_iterator = getDTM(root).getAxisIterator(m_axis); 55 m_iterator.setStartNode(root); 56 } 57 58 /** 59 * Detaches the walker from the set which it iterated over, releasing 60 * any computational resources and placing the iterator in the INVALID 61 * state. 62 */ 63 public void detach() 64 { 65 m_iterator = null; 66 super.detach(); 67 } 68 69 /** 70 * Get the next node in document order on the axes. 71 * 72 * @return the next node in document order on the axes, or null. 73 */ 74 protected int getNextNode() 75 { 76 if (m_foundLast) 77 return DTM.NULL; 78 79 int next = m_iterator.next(); 80 81 if (m_isFresh) 82 m_isFresh = false; 83 84 if (DTM.NULL == next) 85 this.m_foundLast = true; 86 87 return next; 88 } 89 90 91 /** 92 * Tells if this is a reverse axes. Overrides AxesWalker#isReverseAxes. 93 * 94 * @return true for this class. 95 */ 96 public boolean isReverseAxes() 97 { 98 return true; 99 } 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 } 248