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 }