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