blob: fb9d4ce6fea6af40af4afbc6a1666deff1e3a6fd [file] [log] [blame]
package org.apache.xpath.axes;
import javax.xml.transform.TransformerException;
import org.apache.xml.dtm.DTM;
import org.apache.xml.dtm.DTMAxisIterator;
import org.apache.xml.dtm.DTMFilter;
import org.apache.xml.dtm.DTMIterator;
import org.apache.xpath.Expression;
import org.apache.xpath.XPathContext;
import org.apache.xpath.compiler.Compiler;
/**
* <meta name="usage" content="advanced"/>
* This class implements a general iterator for
* those LocationSteps with only one step, and perhaps a predicate.
* @see org.apache.xpath.axes.WalkerFactory#newLocPathIterator
*/
public class OneStepIterator extends ChildTestIterator
{
/** The traversal axis from where the nodes will be filtered. */
protected int m_axis = -1;
/** The DTM inner traversal class, that corresponds to the super axis. */
protected DTMAxisIterator m_iterator;
/**
* Create a OneStepIterator object.
*
* @param compiler A reference to the Compiler that contains the op map.
* @param opPos The position within the op map, which contains the
* location path expression for this itterator.
*
* @throws javax.xml.transform.TransformerException
*/
OneStepIterator(Compiler compiler, int opPos, int analysis)
throws javax.xml.transform.TransformerException
{
super(compiler, opPos, analysis);
int firstStepPos = compiler.getFirstChildPos(opPos);
m_axis = WalkerFactory.getAxisFromStep(compiler, firstStepPos);
}
/**
* Create a OneStepIterator object.
*
* @param iterator The DTM iterator which this iterator will use.
* @param axis One of Axis.Child, etc., or -1 if the axis is unknown.
*
* @throws javax.xml.transform.TransformerException
*/
public OneStepIterator(DTMAxisIterator iterator, int axis)
throws javax.xml.transform.TransformerException
{
super(null);
m_iterator = iterator;
m_axis = axis;
int whatToShow = DTMFilter.SHOW_ALL;
initNodeTest(whatToShow);
}
/**
* 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(m_axis > -1)
m_iterator = m_cdtm.getAxisIterator(m_axis);
m_iterator.setStartNode(m_context);
}
/**
* Get the next node via getFirstAttribute && getNextAttribute.
*/
protected int getNextNode()
{
return m_lastFetched = m_iterator.next();
}
/**
* Get a cloned iterator.
*
* @return A new iterator that can be used without mutating this one.
*
* @throws CloneNotSupportedException
*/
public Object clone() throws CloneNotSupportedException
{
// Do not access the location path itterator during this operation!
OneStepIterator clone = (OneStepIterator) super.clone();
if(m_iterator != null)
{
clone.m_iterator = m_iterator.cloneIterator();
}
return clone;
}
/**
* Get a cloned Iterator that is reset to the beginning
* of the query.
*
* @return A cloned NodeIterator set of the start of the query.
*
* @throws CloneNotSupportedException
*/
public DTMIterator cloneWithReset() throws CloneNotSupportedException
{
OneStepIterator clone = (OneStepIterator) super.cloneWithReset();
clone.m_iterator = m_iterator;
return clone;
}
/**
* Tells if this is a reverse axes. Overrides AxesWalker#isReverseAxes.
*
* @return true for this class.
*/
public boolean isReverseAxes()
{
return m_iterator.isReverse();
}
/**
* Get the current sub-context position. In order to do the
* reverse axes count, for the moment this re-searches the axes
* up to the predicate. An optimization on this is to cache
* the nodes searched, but, for the moment, this case is probably
* rare enough that the added complexity isn't worth it.
*
* @param predicateIndex The predicate index of the proximity position.
*
* @return The pridicate index, or -1.
*/
protected int getProximityPosition(int predicateIndex)
{
if(!isReverseAxes())
return super.getProximityPosition(predicateIndex);
// A negative predicate index seems to occur with
// (preceding-sibling::*|following-sibling::*)/ancestor::*[position()]/*[position()]
// -sb
if(predicateIndex < 0)
return -1;
if (m_proximityPositions[predicateIndex] <= 0)
{
XPathContext xctxt = getXPathContext();
try
{
OneStepIterator clone = (OneStepIterator) this.clone();
int root = getRoot();
xctxt.pushCurrentNode(root);
clone.setRoot(root, xctxt);
// clone.setPredicateCount(predicateIndex);
clone.m_predCount = predicateIndex;
// Count 'em all
int count = 1;
int next;
while (DTM.NULL != (next = clone.nextNode()))
{
count++;
}
m_proximityPositions[predicateIndex] += count;
}
catch (CloneNotSupportedException cnse)
{
// can't happen
}
finally
{
xctxt.popCurrentNode();
}
}
return m_proximityPositions[predicateIndex];
}
/**
* Count backwards one proximity position.
*
* @param i The predicate index.
*/
protected void countProximityPosition(int i)
{
if(!isReverseAxes())
super.countProximityPosition(i);
else if (i < m_proximityPositions.length)
m_proximityPositions[i]--;
}
/**
* Reset the iterator.
*/
public void reset()
{
super.reset();
if(null != m_iterator)
m_iterator.reset();
}
/**
* Returns the axis being iterated, if it is known.
*
* @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
* types.
*/
public int getAxis()
{
return m_axis;
}
/**
* @see Expression#deepEquals(Expression)
*/
public boolean deepEquals(Expression expr)
{
if(!super.deepEquals(expr))
return false;
if(m_axis != ((OneStepIterator)expr).m_axis)
return false;
return true;
}
}