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 */ FilterExprIteratorSimple()54 public FilterExprIteratorSimple() 55 { 56 super(null); 57 } 58 59 /** 60 * Create a FilterExprIteratorSimple object. 61 * 62 */ FilterExprIteratorSimple(Expression expr)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 */ setRoot(int context, Object environment)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 */ executeFilterExpr(int context, XPathContext xctxt, PrefixResolver prefixResolver, boolean isTopLevel, int stackFrame, Expression expr )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 */ nextNode()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 */ detach()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 */ fixupVariables(java.util.Vector vars, int globalsSize)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 */ getInnerExpression()210 public Expression getInnerExpression() 211 { 212 return m_expr; 213 } 214 215 /** 216 * Set the inner contained expression of this filter. 217 */ setInnerExpression(Expression expr)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 */ getAnalysisBits()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 */ isDocOrdered()244 public boolean isDocOrdered() 245 { 246 return m_exprObj.isDocOrdered(); 247 } 248 249 class filterExprOwner implements ExpressionOwner 250 { 251 /** 252 * @see ExpressionOwner#getExpression() 253 */ getExpression()254 public Expression getExpression() 255 { 256 return m_expr; 257 } 258 259 /** 260 * @see ExpressionOwner#setExpression(Expression) 261 */ setExpression(Expression exp)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 */ callPredicateVisitors(XPathVisitor visitor)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 */ deepEquals(Expression expr)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 */ getAxis()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