001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: FilterExprIteratorSimple.java 468655 2006-10-28 07:12:06Z minchau $ 020 */ 021 package org.apache.xpath.axes; 022 023 import org.apache.xml.dtm.Axis; 024 import org.apache.xml.dtm.DTM; 025 import org.apache.xml.utils.PrefixResolver; 026 import org.apache.xpath.Expression; 027 import org.apache.xpath.ExpressionOwner; 028 import org.apache.xpath.VariableStack; 029 import org.apache.xpath.XPathContext; 030 import org.apache.xpath.XPathVisitor; 031 import org.apache.xpath.objects.XNodeSet; 032 033 /** 034 * Class to use for one-step iteration that doesn't have a predicate, and 035 * doesn't need to set the context. 036 */ 037 public class FilterExprIteratorSimple extends LocPathIterator 038 { 039 static final long serialVersionUID = -6978977187025375579L; 040 /** The contained expression. Should be non-null. 041 * @serial */ 042 private Expression m_expr; 043 044 /** The result of executing m_expr. Needs to be deep cloned on clone op. */ 045 transient private XNodeSet m_exprObj; 046 047 private boolean m_mustHardReset = false; 048 private boolean m_canDetachNodeset = true; 049 050 /** 051 * Create a FilterExprIteratorSimple object. 052 * 053 */ 054 public FilterExprIteratorSimple() 055 { 056 super(null); 057 } 058 059 /** 060 * Create a FilterExprIteratorSimple object. 061 * 062 */ 063 public FilterExprIteratorSimple(Expression expr) 064 { 065 super(null); 066 m_expr = expr; 067 } 068 069 /** 070 * Initialize the context values for this expression 071 * after it is cloned. 072 * 073 * @param context The XPath runtime context for this 074 * transformation. 075 */ 076 public void setRoot(int context, Object environment) 077 { 078 super.setRoot(context, environment); 079 m_exprObj = executeFilterExpr(context, m_execContext, getPrefixResolver(), 080 getIsTopLevel(), m_stackFrame, m_expr); 081 } 082 083 /** 084 * Execute the expression. Meant for reuse by other FilterExpr iterators 085 * that are not derived from this object. 086 */ 087 public static XNodeSet executeFilterExpr(int context, XPathContext xctxt, 088 PrefixResolver prefixResolver, 089 boolean isTopLevel, 090 int stackFrame, 091 Expression expr ) 092 throws org.apache.xml.utils.WrappedRuntimeException 093 { 094 PrefixResolver savedResolver = xctxt.getNamespaceContext(); 095 XNodeSet result = null; 096 097 try 098 { 099 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