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: FilterExprWalker.java 469367 2006-10-31 04:41:08Z minchau $ 20 */ 21 package org.apache.xpath.axes; 22 23 import org.apache.xml.dtm.Axis; 24 import org.apache.xml.dtm.DTM; 25 import org.apache.xml.dtm.DTMIterator; 26 import org.apache.xpath.Expression; 27 import org.apache.xpath.ExpressionOwner; 28 import org.apache.xpath.XPathContext; 29 import org.apache.xpath.XPathVisitor; 30 import org.apache.xpath.compiler.Compiler; 31 import org.apache.xpath.compiler.OpCodes; 32 import org.apache.xpath.objects.XNodeSet; 33 34 /** 35 * Walker for the OP_VARIABLE, or OP_EXTFUNCTION, or OP_FUNCTION, or OP_GROUP, 36 * op codes. 37 * @see <a href="http://www.w3.org/TR/xpath#NT-FilterExpr">XPath FilterExpr descriptions</a> 38 */ 39 public class FilterExprWalker extends AxesWalker 40 { 41 static final long serialVersionUID = 5457182471424488375L; 42 43 /** 44 * Construct a FilterExprWalker using a LocPathIterator. 45 * 46 * @param locPathIterator non-null reference to the parent iterator. 47 */ 48 public FilterExprWalker(WalkingIterator locPathIterator) 49 { 50 super(locPathIterator, Axis.FILTEREDLIST); 51 } 52 53 /** 54 * Init a FilterExprWalker. 55 * 56 * @param compiler non-null reference to the Compiler that is constructing. 57 * @param opPos positive opcode position for this step. 58 * @param stepType The type of step. 59 * 60 * @throws javax.xml.transform.TransformerException 61 */ 62 public void init(Compiler compiler, int opPos, int stepType) 63 throws javax.xml.transform.TransformerException 64 { 65 66 super.init(compiler, opPos, stepType); 67 68 // Smooth over an anomily in the opcode map... 69 switch (stepType) 70 { 71 case OpCodes.OP_FUNCTION : 72 case OpCodes.OP_EXTFUNCTION : 73 m_mustHardReset = true; 74 case OpCodes.OP_GROUP : 75 case OpCodes.OP_VARIABLE : 76 m_expr = compiler.compile(opPos); 77 m_expr.exprSetParent(this); 78 //if((OpCodes.OP_FUNCTION == stepType) && (m_expr instanceof org.apache.xalan.templates.FuncKey)) 79 if(m_expr instanceof org.apache.xpath.operations.Variable) 80 { 81 // hack/temp workaround 82 m_canDetachNodeset = false; 83 } 84 break; 85 default : 86 m_expr = compiler.compile(opPos + 2); 87 m_expr.exprSetParent(this); 88 } 89 // if(m_expr instanceof WalkingIterator) 90 // { 91 // WalkingIterator wi = (WalkingIterator)m_expr; 92 // if(wi.getFirstWalker() instanceof FilterExprWalker) 93 // { 94 // FilterExprWalker fw = (FilterExprWalker)wi.getFirstWalker(); 95 // if(null == fw.getNextWalker()) 96 // { 97 // m_expr = fw.m_expr; 98 // m_expr.exprSetParent(this); 99 // } 100 // } 101 // 102 // } 103 } 104 105 /** 106 * Detaches the walker from the set which it iterated over, releasing 107 * any computational resources and placing the iterator in the INVALID 108 * state. 109 */ 110 public void detach() 111 { 112 super.detach(); 113 if (m_canDetachNodeset) 114 { 115 m_exprObj.detach(); 116 } 117 m_exprObj = null; 118 } 119 120 /** 121 * Set the root node of the TreeWalker. 122 * 123 * @param root non-null reference to the root, or starting point of 124 * the query. 125 */ 126 public void setRoot(int root) 127 { 128 129 super.setRoot(root); 130 131 m_exprObj = FilterExprIteratorSimple.executeFilterExpr(root, 132 m_lpi.getXPathContext(), m_lpi.getPrefixResolver(), 133 m_lpi.getIsTopLevel(), m_lpi.m_stackFrame, m_expr); 134 135 } 136 137 /** 138 * Get a cloned FilterExprWalker. 139 * 140 * @return A new FilterExprWalker that can be used without mutating this one. 141 * 142 * @throws CloneNotSupportedException 143 */ 144 public Object clone() throws CloneNotSupportedException 145 { 146 147 FilterExprWalker clone = (FilterExprWalker) super.clone(); 148 149 if (null != m_exprObj) 150 clone.m_exprObj = (XNodeSet) m_exprObj.clone(); 151 152 return clone; 153 } 154 155 /** 156 * This method needs to override AxesWalker.acceptNode because FilterExprWalkers 157 * don't need to, and shouldn't, do a node test. 158 * @param n The node to check to see if it passes the filter or not. 159 * @return a constant to determine whether the node is accepted, 160 * rejected, or skipped, as defined above . 161 */ 162 public short acceptNode(int n) 163 { 164 165 try 166 { 167 if (getPredicateCount() > 0) 168 { 169 countProximityPosition(0); 170 171 if (!executePredicates(n, m_lpi.getXPathContext())) 172 return DTMIterator.FILTER_SKIP; 173 } 174 175 return DTMIterator.FILTER_ACCEPT; 176 } 177 catch (javax.xml.transform.TransformerException se) 178 { 179 throw new RuntimeException(se.getMessage()); 180 } 181 } 182 183 /** 184 * Moves the <code>TreeWalker</code> to the next visible node in document 185 * order relative to the current node, and returns the new node. If the 186 * current node has no next node, or if the search for nextNode attempts 187 * to step upward from the TreeWalker's root node, returns 188 * <code>null</code> , and retains the current node. 189 * @return The new node, or <code>null</code> if the current node has no 190 * next node in the TreeWalker's logical view. 191 */ 192 public int getNextNode() 193 { 194 195 if (null != m_exprObj) 196 { 197 int next = m_exprObj.nextNode(); 198 return next; 199 } 200 else 201 return DTM.NULL; 202 } 203 204 /** 205 * Get the index of the last node that can be itterated to. 206 * 207 * 208 * @param xctxt XPath runtime context. 209 * 210 * @return the index of the last node that can be itterated to. 211 */ 212 public int getLastPos(XPathContext xctxt) 213 { 214 return m_exprObj.getLength(); 215 } 216 217 /** The contained expression. Should be non-null. 218 * @serial */ 219 private Expression m_expr; 220 221 /** The result of executing m_expr. Needs to be deep cloned on clone op. */ 222 transient private XNodeSet m_exprObj; 223 224 private boolean m_mustHardReset = false; 225 private boolean m_canDetachNodeset = true; 226 227 /** 228 * This function is used to fixup variables from QNames to stack frame 229 * indexes at stylesheet build time. 230 * @param vars List of QNames that correspond to variables. This list 231 * should be searched backwards for the first qualified name that 232 * corresponds to the variable reference qname. The position of the 233 * QName in the vector from the start of the vector will be its position 234 * in the stack frame (but variables above the globalsTop value will need 235 * to be offset to the current stack frame). 236 */ 237 public void fixupVariables(java.util.Vector vars, int globalsSize) 238 { 239 super.fixupVariables(vars, globalsSize); 240 m_expr.fixupVariables(vars, globalsSize); 241 } 242 243 /** 244 * Get the inner contained expression of this filter. 245 */ 246 public Expression getInnerExpression() 247 { 248 return m_expr; 249 } 250 251 /** 252 * Set the inner contained expression of this filter. 253 */ 254 public void setInnerExpression(Expression expr) 255 { 256 expr.exprSetParent(this); 257 m_expr = expr; 258 } 259 260 261 /** 262 * Get the analysis bits for this walker, as defined in the WalkerFactory. 263 * @return One of WalkerFactory#BIT_DESCENDANT, etc. 264 */ 265 public int getAnalysisBits() 266 { 267 if (null != m_expr && m_expr instanceof PathComponent) 268 { 269 return ((PathComponent) m_expr).getAnalysisBits(); 270 } 271 return WalkerFactory.BIT_FILTER; 272 } 273 274 /** 275 * Returns true if all the nodes in the iteration well be returned in document 276 * order. 277 * Warning: This can only be called after setRoot has been called! 278 * 279 * @return true as a default. 280 */ 281 public boolean isDocOrdered() 282 { 283 return m_exprObj.isDocOrdered(); 284 } 285 286 /** 287 * Returns the axis being iterated, if it is known. 288 * 289 * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple 290 * types. 291 */ 292 public int getAxis() 293 { 294 return m_exprObj.getAxis(); 295 } 296 297 class filterExprOwner implements ExpressionOwner 298 { 299 /** 300 * @see ExpressionOwner#getExpression() 301 */ 302 public Expression getExpression() 303 { 304 return m_expr; 305 } 306 307 /** 308 * @see ExpressionOwner#setExpression(Expression) 309 */ 310 public void setExpression(Expression exp) 311 { 312 exp.exprSetParent(FilterExprWalker.this); 313 m_expr = exp; 314 } 315 } 316 317 /** 318 * This will traverse the heararchy, calling the visitor for 319 * each member. If the called visitor method returns 320 * false, the subtree should not be called. 321 * 322 * @param visitor The visitor whose appropriate method will be called. 323 */ 324 public void callPredicateVisitors(XPathVisitor visitor) 325 { 326 m_expr.callVisitors(new filterExprOwner(), visitor); 327 328 super.callPredicateVisitors(visitor); 329 } 330 331 332 /** 333 * @see Expression#deepEquals(Expression) 334 */ 335 public boolean deepEquals(Expression expr) 336 { 337 if (!super.deepEquals(expr)) 338 return false; 339 340 FilterExprWalker walker = (FilterExprWalker)expr; 341 if(!m_expr.deepEquals(walker.m_expr)) 342 return false; 343 344 return true; 345 } 346 347 348 349 } 350