/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Id: WalkingIterator.java 469314 2006-10-30 23:31:59Z minchau $ */ package org.apache.xpath.axes; import org.apache.xml.dtm.DTM; import org.apache.xml.utils.PrefixResolver; import org.apache.xpath.Expression; import org.apache.xpath.ExpressionOwner; import org.apache.xpath.VariableStack; import org.apache.xpath.XPathVisitor; import org.apache.xpath.compiler.Compiler; import org.apache.xpath.compiler.OpMap; /** * Location path iterator that uses Walkers. */ public class WalkingIterator extends LocPathIterator implements ExpressionOwner { static final long serialVersionUID = 9110225941815665906L; /** * Create a WalkingIterator iterator, including creation * of step walkers from the opcode list, and call back * into the Compiler to create predicate expressions. * * @param compiler The Compiler which is creating * this expression. * @param opPos The position of this iterator in the * opcode list from the compiler. * @param shouldLoadWalkers True if walkers should be * loaded, or false if this is a derived iterator and * it doesn't wish to load child walkers. * * @throws javax.xml.transform.TransformerException */ WalkingIterator( Compiler compiler, int opPos, int analysis, boolean shouldLoadWalkers) throws javax.xml.transform.TransformerException { super(compiler, opPos, analysis, shouldLoadWalkers); int firstStepPos = OpMap.getFirstChildPos(opPos); if (shouldLoadWalkers) { m_firstWalker = WalkerFactory.loadWalkers(this, compiler, firstStepPos, 0); m_lastUsedWalker = m_firstWalker; } } /** * Create a WalkingIterator object. * * @param nscontext The namespace context for this iterator, * should be OK if null. */ public WalkingIterator(PrefixResolver nscontext) { super(nscontext); } /** * Get the analysis bits for this walker, as defined in the WalkerFactory. * @return One of WalkerFactory#BIT_DESCENDANT, etc. */ public int getAnalysisBits() { int bits = 0; if (null != m_firstWalker) { AxesWalker walker = m_firstWalker; while (null != walker) { int bit = walker.getAnalysisBits(); bits |= bit; walker = walker.getNextWalker(); } } return bits; } /** * Get a cloned WalkingIterator that holds the same * position as this iterator. * * @return A clone of this iterator that holds the same node position. * * @throws CloneNotSupportedException */ public Object clone() throws CloneNotSupportedException { WalkingIterator clone = (WalkingIterator) super.clone(); // clone.m_varStackPos = this.m_varStackPos; // clone.m_varStackContext = this.m_varStackContext; if (null != m_firstWalker) { clone.m_firstWalker = m_firstWalker.cloneDeep(clone, null); } return clone; } /** * Reset the iterator. */ public void reset() { super.reset(); if (null != m_firstWalker) { m_lastUsedWalker = m_firstWalker; m_firstWalker.setRoot(m_context); } } /** * Initialize the context values for this expression * after it is cloned. * * @param context The XPath runtime context for this * transformation. */ public void setRoot(int context, Object environment) { super.setRoot(context, environment); if(null != m_firstWalker) { m_firstWalker.setRoot(context); m_lastUsedWalker = m_firstWalker; } } /** * Returns the next node in the set and advances the position of the * iterator in the set. After a NodeIterator is created, the first call * to nextNode() returns the first node in the set. * @return The next Node in the set being iterated over, or * null if there are no more members in that set. */ public int nextNode() { if(m_foundLast) return DTM.NULL; // If the variable stack position is not -1, we'll have to // set our position in the variable stack, so our variable access // will be correct. Iterators that are at the top level of the // expression need to reset the variable stack, while iterators // in predicates do not need to, and should not, since their execution // may be much later than top-level iterators. // m_varStackPos is set in setRoot, which is called // from the execute method. if (-1 == m_stackFrame) { return returnNextNode(m_firstWalker.nextNode()); } else { VariableStack vars = m_execContext.getVarStack(); // These three statements need to be combined into one operation. int savedStart = vars.getStackFrame(); vars.setStackFrame(m_stackFrame); int n = returnNextNode(m_firstWalker.nextNode()); // These two statements need to be combined into one operation. vars.setStackFrame(savedStart); return n; } } /** * Get the head of the walker list. * * @return The head of the walker list, or null * if this iterator does not implement walkers. * @xsl.usage advanced */ public final AxesWalker getFirstWalker() { return m_firstWalker; } /** * Set the head of the walker list. * * @param walker Should be a valid AxesWalker. * @xsl.usage advanced */ public final void setFirstWalker(AxesWalker walker) { m_firstWalker = walker; } /** * Set the last used walker. * * @param walker The last used walker, or null. * @xsl.usage advanced */ public final void setLastUsedWalker(AxesWalker walker) { m_lastUsedWalker = walker; } /** * Get the last used walker. * * @return The last used walker, or null. * @xsl.usage advanced */ public final AxesWalker getLastUsedWalker() { return m_lastUsedWalker; } /** * Detaches the iterator from the set which it iterated over, releasing * any computational resources and placing the iterator in the INVALID * state. Afterdetach has been invoked, calls to * nextNode orpreviousNode will raise the * exception INVALID_STATE_ERR. */ public void detach() { if(m_allowDetach) { AxesWalker walker = m_firstWalker; while (null != walker) { walker.detach(); walker = walker.getNextWalker(); } m_lastUsedWalker = null; // Always call the superclass detach last! super.detach(); } } /** * This function is used to fixup variables from QNames to stack frame * indexes at stylesheet build time. * @param vars List of QNames that correspond to variables. This list * should be searched backwards for the first qualified name that * corresponds to the variable reference qname. The position of the * QName in the vector from the start of the vector will be its position * in the stack frame (but variables above the globalsTop value will need * to be offset to the current stack frame). */ public void fixupVariables(java.util.Vector vars, int globalsSize) { m_predicateIndex = -1; AxesWalker walker = m_firstWalker; while (null != walker) { walker.fixupVariables(vars, globalsSize); walker = walker.getNextWalker(); } } /** * @see org.apache.xpath.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor) */ public void callVisitors(ExpressionOwner owner, XPathVisitor visitor) { if(visitor.visitLocationPath(owner, this)) { if(null != m_firstWalker) { m_firstWalker.callVisitors(this, visitor); } } } /** The last used step walker in the walker list. * @serial */ protected AxesWalker m_lastUsedWalker; /** The head of the step walker list. * @serial */ protected AxesWalker m_firstWalker; /** * @see ExpressionOwner#getExpression() */ public Expression getExpression() { return m_firstWalker; } /** * @see ExpressionOwner#setExpression(Expression) */ public void setExpression(Expression exp) { exp.exprSetParent(this); m_firstWalker = (AxesWalker)exp; } /** * @see Expression#deepEquals(Expression) */ public boolean deepEquals(Expression expr) { if (!super.deepEquals(expr)) return false; AxesWalker walker1 = m_firstWalker; AxesWalker walker2 = ((WalkingIterator)expr).m_firstWalker; while ((null != walker1) && (null != walker2)) { if(!walker1.deepEquals(walker2)) return false; walker1 = walker1.getNextWalker(); walker2 = walker2.getNextWalker(); } if((null != walker1) || (null != walker2)) return false; return true; } }