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