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