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