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.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.XPathContext; 31 import com.sun.org.apache.xpath.internal.XPathVisitor; 32 import com.sun.org.apache.xpath.internal.objects.XNodeSet; 33 import java.util.List; 34 35 /** 36 * Class to use for one-step iteration that doesn't have a predicate, and 37 * doesn't need to set the context. 38 * 39 * @LastModified: Oct 2017 40 */ 41 public class FilterExprIteratorSimple extends LocPathIterator 42 { 43 static final long serialVersionUID = -6978977187025375579L; 44 /** The contained expression. Should be non-null. 45 * @serial */ 46 private Expression m_expr; 47 48 /** The result of executing m_expr. Needs to be deep cloned on clone op. */ 49 transient private XNodeSet m_exprObj; 50 51 private boolean m_mustHardReset = false; 52 private boolean m_canDetachNodeset = true; 53 54 /** 55 * Create a FilterExprIteratorSimple object. 56 * 57 */ 58 public FilterExprIteratorSimple() 59 { 60 super(null); 61 } 62 63 /** 64 * Create a FilterExprIteratorSimple object. 65 * 66 */ 67 public FilterExprIteratorSimple(Expression expr) 68 { 69 super(null); 70 m_expr = expr; 71 } 72 73 /** 74 * Initialize the context values for this expression 75 * after it is cloned. 76 * 77 * @param context The XPath runtime context for this 78 * transformation. 79 */ 80 public void setRoot(int context, Object environment) 81 { 82 super.setRoot(context, environment); 83 m_exprObj = executeFilterExpr(context, m_execContext, getPrefixResolver(), 84 getIsTopLevel(), m_stackFrame, m_expr); 85 } 86 87 /** 88 * Execute the expression. Meant for reuse by other FilterExpr iterators 89 * that are not derived from this object. 90 */ 91 public static XNodeSet executeFilterExpr(int context, XPathContext xctxt, 92 PrefixResolver prefixResolver, 93 boolean isTopLevel, 94 int stackFrame, 95 Expression expr ) 96 throws com.sun.org.apache.xml.internal.utils.WrappedRuntimeException 97 { 98 PrefixResolver savedResolver = xctxt.getNamespaceContext(); 99 XNodeSet result = null; 100 101 try 102 { 103 xctxt.pushCurrentNode(context); 104 xctxt.setNamespaceContext(prefixResolver); 105 106 // The setRoot operation can take place with a reset operation, 107 // and so we may not be in the context of LocPathIterator#nextNode, 108 // so we have to set up the variable context, execute the expression, 109 // and then restore the variable context. 110 111 if (isTopLevel) 112 { 113 // System.out.println("calling m_expr.execute(getXPathContext())"); 114 VariableStack vars = xctxt.getVarStack(); 115 116 // These three statements need to be combined into one operation. 117 int savedStart = vars.getStackFrame(); 118 vars.setStackFrame(stackFrame); 119 120 result = (com.sun.org.apache.xpath.internal.objects.XNodeSet) expr.execute(xctxt); 121 result.setShouldCacheNodes(true); 122 123 // These two statements need to be combined into one operation. 124 vars.setStackFrame(savedStart); 125 } 126 else 127 result = (com.sun.org.apache.xpath.internal.objects.XNodeSet) expr.execute(xctxt); 128 129 } 130 catch (javax.xml.transform.TransformerException se) 131 { 132 133 // TODO: Fix... 134 throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(se); 135 } 136 finally 137 { 138 xctxt.popCurrentNode(); 139 xctxt.setNamespaceContext(savedResolver); 140 } 141 return result; 142 } 143 144 /** 145 * Returns the next node in the set and advances the position of the 146 * iterator in the set. After a NodeIterator is created, the first call 147 * to nextNode() returns the first node in the set. 148 * 149 * @return The next <code>Node</code> in the set being iterated over, or 150 * <code>null</code> if there are no more members in that set. 151 */ 152 public int nextNode() 153 { 154 if(m_foundLast) 155 return DTM.NULL; 156 157 int next; 158 159 if (null != m_exprObj) 160 { 161 m_lastFetched = next = m_exprObj.nextNode(); 162 } 163 else 164 m_lastFetched = next = DTM.NULL; 165 166 // m_lastFetched = next; 167 if (DTM.NULL != next) 168 { 169 m_pos++; 170 return next; 171 } 172 else 173 { 174 m_foundLast = true; 175 176 return DTM.NULL; 177 } 178 } 179 180 /** 181 * Detaches the walker from the set which it iterated over, releasing 182 * any computational resources and placing the iterator in the INVALID 183 * state. 184 */ 185 public void detach() 186 { 187 if(m_allowDetach) 188 { 189 super.detach(); 190 m_exprObj.detach(); 191 m_exprObj = null; 192 } 193 } 194 195 /** 196 * This function is used to fixup variables from QNames to stack frame 197 * indexes at stylesheet build time. 198 * @param vars List of QNames that correspond to variables. This list 199 * should be searched backwards for the first qualified name that 200 * corresponds to the variable reference qname. The position of the 201 * QName in the vector from the start of the vector will be its position 202 * in the stack frame (but variables above the globalsTop value will need 203 * to be offset to the current stack frame). 204 */ 205 public void fixupVariables(List<QName> vars, int globalsSize) 206 { 207 super.fixupVariables(vars, globalsSize); 208 m_expr.fixupVariables(vars, globalsSize); 209 } 210 211 /** 212 * Get the inner contained expression of this filter. 213 */ 214 public Expression getInnerExpression() 215 { 216 return m_expr; 217 } 218 219 /** 220 * Set the inner contained expression of this filter. 221 */ 222 public void setInnerExpression(Expression expr) 223 { 224 expr.exprSetParent(this); 225 m_expr = expr; 226 } 227 228 /** 229 * Get the analysis bits for this walker, as defined in the WalkerFactory. 230 * @return One of WalkerFactory#BIT_DESCENDANT, etc. 231 */ 232 public int getAnalysisBits() 233 { 234 if (null != m_expr && m_expr instanceof PathComponent) 235 { 236 return ((PathComponent) m_expr).getAnalysisBits(); 237 } 238 return WalkerFactory.BIT_FILTER; 239 } 240 241 /** 242 * Returns true if all the nodes in the iteration well be returned in document 243 * order. 244 * Warning: This can only be called after setRoot has been called! 245 * 246 * @return true as a default. 247 */ 248 public boolean isDocOrdered() 249 { 250 return m_exprObj.isDocOrdered(); 251 } 252 253 class filterExprOwner implements ExpressionOwner 254 { 255 /** 256 * @see ExpressionOwner#getExpression() 257 */ 258 public Expression getExpression() 259 { 260 return m_expr; 261 } 262 263 /** 264 * @see ExpressionOwner#setExpression(Expression) 265 */ 266 public void setExpression(Expression exp) 267 { 268 exp.exprSetParent(FilterExprIteratorSimple.this); 269 m_expr = exp; 270 } 271 272 } 273 274 /** 275 * This will traverse the heararchy, calling the visitor for 276 * each member. If the called visitor method returns 277 * false, the subtree should not be called. 278 * 279 * @param visitor The visitor whose appropriate method will be called. 280 */ 281 public void callPredicateVisitors(XPathVisitor visitor) 282 { 283 m_expr.callVisitors(new filterExprOwner(), visitor); 284 285 super.callPredicateVisitors(visitor); 286 } 287 288 /** 289 * @see Expression#deepEquals(Expression) 290 */ 291 public boolean deepEquals(Expression expr) 292 { 293 if (!super.deepEquals(expr)) 294 return false; 295 296 FilterExprIteratorSimple fet = (FilterExprIteratorSimple) expr; 297 if (!m_expr.deepEquals(fet.m_expr)) 298 return false; 299 300 return true; 301 } 302 303 /** 304 * Returns the axis being iterated, if it is known. 305 * 306 * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple 307 * types. 308 */ 309 public int getAxis() 310 { 311 if(null != m_exprObj) 312 return m_exprObj.getAxis(); 313 else 314 return Axis.FILTEREDLIST; 315 } 316 317 318 }