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: WalkingIterator.java 469314 2006-10-30 23:31:59Z minchau $ 20 */ 21 package org.apache.xpath.axes; 22 23 import org.apache.xml.dtm.DTM; 24 import org.apache.xml.utils.PrefixResolver; 25 import org.apache.xpath.Expression; 26 import org.apache.xpath.ExpressionOwner; 27 import org.apache.xpath.VariableStack; 28 import org.apache.xpath.XPathVisitor; 29 import org.apache.xpath.compiler.Compiler; 30 import org.apache.xpath.compiler.OpMap; 31 32 /** 33 * Location path iterator that uses Walkers. 34 */ 35 36 public class WalkingIterator extends LocPathIterator implements ExpressionOwner 37 { 38 static final long serialVersionUID = 9110225941815665906L; 39 /** 40 * Create a WalkingIterator iterator, including creation 41 * of step walkers from the opcode list, and call back 42 * into the Compiler to create predicate expressions. 43 * 44 * @param compiler The Compiler which is creating 45 * this expression. 46 * @param opPos The position of this iterator in the 47 * opcode list from the compiler. 48 * @param shouldLoadWalkers True if walkers should be 49 * loaded, or false if this is a derived iterator and 50 * it doesn't wish to load child walkers. 51 * 52 * @throws javax.xml.transform.TransformerException 53 */ 54 WalkingIterator( 55 Compiler compiler, int opPos, int analysis, boolean shouldLoadWalkers) 56 throws javax.xml.transform.TransformerException 57 { 58 super(compiler, opPos, analysis, shouldLoadWalkers); 59 60 int firstStepPos = OpMap.getFirstChildPos(opPos); 61 62 if (shouldLoadWalkers) 63 { 64 m_firstWalker = WalkerFactory.loadWalkers(this, compiler, firstStepPos, 0); 65 m_lastUsedWalker = m_firstWalker; 66 } 67 } 68 69 /** 70 * Create a WalkingIterator object. 71 * 72 * @param nscontext The namespace context for this iterator, 73 * should be OK if null. 74 */ 75 public WalkingIterator(PrefixResolver nscontext) 76 { 77 78 super(nscontext); 79 } 80 81 82 /** 83 * Get the analysis bits for this walker, as defined in the WalkerFactory. 84 * @return One of WalkerFactory#BIT_DESCENDANT, etc. 85 */ 86 public int getAnalysisBits() 87 { 88 int bits = 0; 89 if (null != m_firstWalker) 90 { 91 AxesWalker walker = m_firstWalker; 92 93 while (null != walker) 94 { 95 int bit = walker.getAnalysisBits(); 96 bits |= bit; 97 walker = walker.getNextWalker(); 98 } 99 } 100 return bits; 101 } 102 103 /** 104 * Get a cloned WalkingIterator that holds the same 105 * position as this iterator. 106 * 107 * @return A clone of this iterator that holds the same node position. 108 * 109 * @throws CloneNotSupportedException 110 */ 111 public Object clone() throws CloneNotSupportedException 112 { 113 114 WalkingIterator clone = (WalkingIterator) super.clone(); 115 116 // clone.m_varStackPos = this.m_varStackPos; 117 // clone.m_varStackContext = this.m_varStackContext; 118 if (null != m_firstWalker) 119 { 120 clone.m_firstWalker = m_firstWalker.cloneDeep(clone, null); 121 } 122 123 return clone; 124 } 125 126 /** 127 * Reset the iterator. 128 */ 129 public void reset() 130 { 131 132 super.reset(); 133 134 if (null != m_firstWalker) 135 { 136 m_lastUsedWalker = m_firstWalker; 137 138 m_firstWalker.setRoot(m_context); 139 } 140 141 } 142 143 /** 144 * Initialize the context values for this expression 145 * after it is cloned. 146 * 147 * @param context The XPath runtime context for this 148 * transformation. 149 */ 150 public void setRoot(int context, Object environment) 151 { 152 153 super.setRoot(context, environment); 154 155 if(null != m_firstWalker) 156 { 157 m_firstWalker.setRoot(context); 158 m_lastUsedWalker = m_firstWalker; 159 } 160 } 161 162 /** 163 * Returns the next node in the set and advances the position of the 164 * iterator in the set. After a NodeIterator is created, the first call 165 * to nextNode() returns the first node in the set. 166 * @return The next <code>Node</code> in the set being iterated over, or 167 * <code>null</code> if there are no more members in that set. 168 */ 169 public int nextNode() 170 { 171 if(m_foundLast) 172 return DTM.NULL; 173 174 // If the variable stack position is not -1, we'll have to 175 // set our position in the variable stack, so our variable access 176 // will be correct. Iterators that are at the top level of the 177 // expression need to reset the variable stack, while iterators 178 // in predicates do not need to, and should not, since their execution 179 // may be much later than top-level iterators. 180 // m_varStackPos is set in setRoot, which is called 181 // from the execute method. 182 if (-1 == m_stackFrame) 183 { 184 return returnNextNode(m_firstWalker.nextNode()); 185 } 186 else 187 { 188 VariableStack vars = m_execContext.getVarStack(); 189 190 // These three statements need to be combined into one operation. 191 int savedStart = vars.getStackFrame(); 192 193 vars.setStackFrame(m_stackFrame); 194 195 int n = returnNextNode(m_firstWalker.nextNode()); 196 197 // These two statements need to be combined into one operation. 198 vars.setStackFrame(savedStart); 199 200 return n; 201 } 202 } 203 204 205 /** 206 * Get the head of the walker list. 207 * 208 * @return The head of the walker list, or null 209 * if this iterator does not implement walkers. 210 * @xsl.usage advanced 211 */ 212 public final AxesWalker getFirstWalker() 213 { 214 return m_firstWalker; 215 } 216 217 /** 218 * Set the head of the walker list. 219 * 220 * @param walker Should be a valid AxesWalker. 221 * @xsl.usage advanced 222 */ 223 public final void setFirstWalker(AxesWalker walker) 224 { 225 m_firstWalker = walker; 226 } 227 228 229 /** 230 * Set the last used walker. 231 * 232 * @param walker The last used walker, or null. 233 * @xsl.usage advanced 234 */ 235 public final void setLastUsedWalker(AxesWalker walker) 236 { 237 m_lastUsedWalker = walker; 238 } 239 240 /** 241 * Get the last used walker. 242 * 243 * @return The last used walker, or null. 244 * @xsl.usage advanced 245 */ 246 public final AxesWalker getLastUsedWalker() 247 { 248 return m_lastUsedWalker; 249 } 250 251 /** 252 * Detaches the iterator from the set which it iterated over, releasing 253 * any computational resources and placing the iterator in the INVALID 254 * state. After<code>detach</code> has been invoked, calls to 255 * <code>nextNode</code> or<code>previousNode</code> will raise the 256 * exception INVALID_STATE_ERR. 257 */ 258 public void detach() 259 { 260 if(m_allowDetach) 261 { 262 AxesWalker walker = m_firstWalker; 263 while (null != walker) 264 { 265 walker.detach(); 266 walker = walker.getNextWalker(); 267 } 268 269 m_lastUsedWalker = null; 270 271 // Always call the superclass detach last! 272 super.detach(); 273 } 274 } 275 276 /** 277 * This function is used to fixup variables from QNames to stack frame 278 * indexes at stylesheet build time. 279 * @param vars List of QNames that correspond to variables. This list 280 * should be searched backwards for the first qualified name that 281 * corresponds to the variable reference qname. The position of the 282 * QName in the vector from the start of the vector will be its position 283 * in the stack frame (but variables above the globalsTop value will need 284 * to be offset to the current stack frame). 285 */ 286 public void fixupVariables(java.util.Vector vars, int globalsSize) 287 { 288 m_predicateIndex = -1; 289 290 AxesWalker walker = m_firstWalker; 291 292 while (null != walker) 293 { 294 walker.fixupVariables(vars, globalsSize); 295 walker = walker.getNextWalker(); 296 } 297 } 298 299 /** 300 * @see org.apache.xpath.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor) 301 */ 302 public void callVisitors(ExpressionOwner owner, XPathVisitor visitor) 303 { 304 if(visitor.visitLocationPath(owner, this)) 305 { 306 if(null != m_firstWalker) 307 { 308 m_firstWalker.callVisitors(this, visitor); 309 } 310 } 311 } 312 313 314 /** The last used step walker in the walker list. 315 * @serial */ 316 protected AxesWalker m_lastUsedWalker; 317 318 /** The head of the step walker list. 319 * @serial */ 320 protected AxesWalker m_firstWalker; 321 322 /** 323 * @see ExpressionOwner#getExpression() 324 */ 325 public Expression getExpression() 326 { 327 return m_firstWalker; 328 } 329 330 /** 331 * @see ExpressionOwner#setExpression(Expression) 332 */ 333 public void setExpression(Expression exp) 334 { 335 exp.exprSetParent(this); 336 m_firstWalker = (AxesWalker)exp; 337 } 338 339 /** 340 * @see Expression#deepEquals(Expression) 341 */ 342 public boolean deepEquals(Expression expr) 343 { 344 if (!super.deepEquals(expr)) 345 return false; 346 347 AxesWalker walker1 = m_firstWalker; 348 AxesWalker walker2 = ((WalkingIterator)expr).m_firstWalker; 349 while ((null != walker1) && (null != walker2)) 350 { 351 if(!walker1.deepEquals(walker2)) 352 return false; 353 walker1 = walker1.getNextWalker(); 354 walker2 = walker2.getNextWalker(); 355 } 356 357 if((null != walker1) || (null != walker2)) 358 return false; 359 360 return true; 361 } 362 363 } 364