blob: 056189d92657d7165fd91cf5834852c728bf0887 [file] [log] [blame]
package org.apache.xpath.axes;
import org.apache.xml.dtm.DTM;
import org.apache.xml.dtm.DTMIterator;
import org.apache.xml.dtm.DTMFilter;
import org.apache.xml.dtm.DTMManager;
// Xalan imports
import org.apache.xpath.res.XPATHErrorResources;
import org.apache.xpath.XPath;
import org.apache.xpath.compiler.OpMap;
import org.apache.xpath.compiler.Compiler;
import org.apache.xpath.compiler.OpCodes;
import org.apache.xpath.compiler.PsuedoNames;
import org.apache.xpath.NodeSetDTM;
import org.apache.xpath.Expression;
import org.apache.xpath.XPathContext;
import org.apache.xpath.objects.XObject;
import org.apache.xml.utils.IntStack;
import org.apache.xml.utils.PrefixResolver;
import org.apache.xml.utils.ObjectPool;
import org.apache.xpath.objects.XNodeSet;
import org.apache.xpath.axes.AxesWalker;
import org.apache.xpath.VariableStack;
/**
* Location path iterator that uses Walkers.
*/
public class WalkingIterator extends LocPathIterator
{
/**
* 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.
*/
protected WalkingIterator(PrefixResolver nscontext)
{
super(nscontext);
}
/**
* 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);
}
}
/**
* 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 <code>Node</code> in the set being iterated over, or
* <code>null</code> if there are no more members in that set.
*/
public int nextNode()
{
// If the cache is on, and the node has already been found, then
// just return from the list.
if (null != m_cachedNodes)
{
if(m_next < m_cachedNodes.size())
{
int next = m_lastFetched = m_currentContextNode
= m_cachedNodes.elementAt(m_next);
incrementNextPosition();
return next;
}
else if(m_foundLast)
{
m_lastFetched = DTM.NULL;
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)
{
if (DTM.NULL == m_firstWalker.getRoot())
{
this.setNextPosition(0);
m_firstWalker.setRoot(m_context);
m_lastUsedWalker = m_firstWalker;
}
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);
if (DTM.NULL == m_firstWalker.getRoot())
{
this.setNextPosition(0);
m_firstWalker.setRoot(m_context);
m_lastUsedWalker = m_firstWalker;
}
int n = returnNextNode(m_firstWalker.nextNode());
// These two statements need to be combined into one operation.
vars.setStackFrame(savedStart);
return n;
}
}
/**
* <meta name="usage" content="advanced"/>
* Get the head of the walker list.
*
* @return The head of the walker list, or null
* if this iterator does not implement walkers.
*/
public final AxesWalker getFirstWalker()
{
return m_firstWalker;
}
/**
* <meta name="usage" content="advanced"/>
* Set the last used walker.
*
* @param walker The last used walker, or null.
*/
public final void setLastUsedWalker(AxesWalker walker)
{
m_lastUsedWalker = walker;
}
/**
* <meta name="usage" content="advanced"/>
* Get the last used walker.
*
* @return The last used walker, or null.
*/
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. After<code>detach</code> has been invoked, calls to
* <code>nextNode</code> or<code>previousNode</code> will raise the
* exception INVALID_STATE_ERR.
*/
public void detach()
{
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();
}
}
/** 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;
}