/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed 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,v 1.10 2004/02/17 04:32:08 minchau Exp $
*/
package com.sun.org.apache.xpath.internal.axes;
import com.sun.org.apache.xml.internal.dtm.DTM;
import com.sun.org.apache.xml.internal.utils.PrefixResolver;
import com.sun.org.apache.xpath.internal.Expression;
import com.sun.org.apache.xpath.internal.ExpressionOwner;
import com.sun.org.apache.xpath.internal.VariableStack;
import com.sun.org.apache.xpath.internal.XPathVisitor;
import com.sun.org.apache.xpath.internal.compiler.Compiler;
/**
* Location path iterator that uses Walkers.
*/
public class WalkingIterator extends LocPathIterator implements ExpressionOwner
{
/**
* 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 = compiler.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 execContext 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 com.sun.org.apache.xpath.internal.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;
}
}