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