blob: c8847450ad3026b8b07fa03544d395db60c62ec7 [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, Lotus
* Development Corporation., http://www.lotus.com. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.xpath.axes;
import javax.xml.transform.TransformerException;
import org.apache.xalan.res.XSLMessages;
import org.apache.xml.dtm.Axis;
import org.apache.xml.dtm.DTMFilter;
import org.apache.xml.dtm.DTMIterator;
import org.apache.xpath.Expression;
import org.apache.xpath.functions.FuncLast;
import org.apache.xpath.functions.FuncPosition;
import org.apache.xpath.functions.Function;
import org.apache.xpath.objects.XNumber;
import org.apache.xpath.operations.Variable;
import org.apache.xpath.parser.Node;
import org.apache.xpath.parser.NodeTest;
import org.apache.xpath.parser.PathExpr;
import org.apache.xpath.parser.PatternAxis;
import org.apache.xpath.parser.Predicates;
import org.apache.xpath.parser.StepExpr;
import org.apache.xpath.res.XPATHErrorResources;
public class WalkerFactory
{
public static boolean isSet(int analysis, int bits)
{
return (0 != (analysis & bits));
}
/**
* Get a corresponding BIT_XXX from an axis.
* @param axis One of Axis.ANCESTOR, etc.
* @return One of BIT_ANCESTOR, etc.
*/
static public int getAnalysisBitFromAxes(int axis)
{
switch (axis) // Generate new traverser
{
case Axis.ANCESTOR :
return BIT_ANCESTOR;
case Axis.ANCESTORORSELF :
return BIT_ANCESTOR_OR_SELF;
case Axis.ATTRIBUTE :
return BIT_ATTRIBUTE;
case Axis.CHILD :
return BIT_CHILD;
case Axis.DESCENDANT :
return BIT_DESCENDANT;
case Axis.DESCENDANTORSELF :
return BIT_DESCENDANT_OR_SELF;
case Axis.FOLLOWING :
return BIT_FOLLOWING;
case Axis.FOLLOWINGSIBLING :
return BIT_FOLLOWING_SIBLING;
case Axis.NAMESPACE :
case Axis.NAMESPACEDECLS :
return BIT_NAMESPACE;
case Axis.PARENT :
return BIT_PARENT;
case Axis.PRECEDING :
return BIT_PRECEDING;
case Axis.PRECEDINGSIBLING :
return BIT_PRECEDING_SIBLING;
case Axis.SELF :
return BIT_SELF;
case Axis.ALLFROMNODE :
return BIT_DESCENDANT_OR_SELF;
// case Axis.PRECEDINGANDANCESTOR :
case Axis.DESCENDANTSFROMROOT :
case Axis.ALL :
case Axis.DESCENDANTSORSELFFROMROOT :
return BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF | BIT_ANY_DESCENDANT_FROM_ROOT;
case Axis.ROOT :
return BIT_ROOT;
case Axis.FILTEREDLIST :
return BIT_FILTER;
default :
return BIT_FILTER;
}
}
/**
* Tell if the given axis goes downword. Bogus name, if you can think of
* a better one, please do tell. This really has to do with inverting
* attribute axis.
* @param axis One of Axis.XXX.
* @return true if the axis is not a child axis and does not go up from
* the axis root.
*/
public static boolean isDownwardAxisOfMany(int axis)
{
return (
(Axis.DESCENDANTORSELF == axis)
|| (Axis.DESCENDANT == axis)
|| (Axis.FOLLOWING == axis)
// || (Axis.FOLLOWINGSIBLING == axis)
|| (Axis.PRECEDING == axis)
// || (Axis.PRECEDINGSIBLING == axis)
);
}
/**
* First 8 bits are the number of top-level location steps. Hopefully
* there will never be more that 255 location steps!!!
*/
public static final int BITS_COUNT = 0x000000FF;
/** 4 bits are reserved for future use. */
public static final int BITS_RESERVED = 0x00000F00;
/** Bit is on if the expression contains a top-level predicate. */
public static final int BIT_PREDICATE = (0x00001000);
/** Bit is on if any of the walkers contain an ancestor step. */
public static final int BIT_ANCESTOR = (0x00001000 << 1);
/** Bit is on if any of the walkers contain an ancestor-or-self step. */
public static final int BIT_ANCESTOR_OR_SELF = (0x00001000 << 2);
/** Bit is on if any of the walkers contain an attribute step. */
public static final int BIT_ATTRIBUTE = (0x00001000 << 3);
/** Bit is on if any of the walkers contain a child step. */
public static final int BIT_CHILD = (0x00001000 << 4);
/** Bit is on if any of the walkers contain a descendant step. */
public static final int BIT_DESCENDANT = (0x00001000 << 5);
/** Bit is on if any of the walkers contain a descendant-or-self step. */
public static final int BIT_DESCENDANT_OR_SELF = (0x00001000 << 6);
/** Bit is on if any of the walkers contain a following step. */
public static final int BIT_FOLLOWING = (0x00001000 << 7);
/** Bit is on if any of the walkers contain a following-sibiling step. */
public static final int BIT_FOLLOWING_SIBLING = (0x00001000 << 8);
/** Bit is on if any of the walkers contain a namespace step. */
public static final int BIT_NAMESPACE = (0x00001000 << 9);
/** Bit is on if any of the walkers contain a parent step. */
public static final int BIT_PARENT = (0x00001000 << 10);
/** Bit is on if any of the walkers contain a preceding step. */
public static final int BIT_PRECEDING = (0x00001000 << 11);
/** Bit is on if any of the walkers contain a preceding-sibling step. */
public static final int BIT_PRECEDING_SIBLING = (0x00001000 << 12);
/** Bit is on if any of the walkers contain a self step. */
public static final int BIT_SELF = (0x00001000 << 13);
/**
* Bit is on if any of the walkers contain a filter (i.e. id(), extension
* function, etc.) step.
*/
public static final int BIT_FILTER = (0x00001000 << 14);
/** Bit is on if any of the walkers contain a root step. */
public static final int BIT_ROOT = (0x00001000 << 15);
/**
* If any of these bits are on, the expression may likely traverse outside
* the given subtree.
*/
public static final int BITMASK_TRAVERSES_OUTSIDE_SUBTREE =
(BIT_NAMESPACE // ??
| BIT_PRECEDING_SIBLING
| BIT_PRECEDING
| BIT_FOLLOWING_SIBLING
| BIT_FOLLOWING
| BIT_PARENT // except parent of attrs.
| BIT_ANCESTOR_OR_SELF | BIT_ANCESTOR | BIT_FILTER | BIT_ROOT);
/**
* Bit is on if any of the walkers can go backwards in document
* order from the context node.
*/
public static final int BIT_BACKWARDS_SELF = (0x00001000 << 16);
/** Found "//foo" pattern */
public static final int BIT_ANY_DESCENDANT_FROM_ROOT = (0x00001000 << 17);
/**
* Bit is on if any of the walkers contain an node() test. This is
* really only useful if the count is 1.
*/
public static final int BIT_NODETEST_ANY = (0x00001000 << 18);
// can't go higher than 18!
/** Bit is on if the expression is a match pattern. */
public static final int BIT_MATCH_PATTERN = (0x00001000 << 19);
/**
* Analyze a step and give information about it's predicates. Right now this
* just returns true or false if the step has a predicate.
*
* @param compiler non-null reference to compiler object that has processed
* the XPath operations into an opcode map.
* @param opPos The opcode position for the step.
* @param stepType The type of step, one of OP_GROUP, etc.
*
* @return true if step has a predicate.
*
* @throws javax.xml.transform.TransformerException
*/
static boolean analyzePredicate(StepExpr stepExpr)
throws javax.xml.transform.TransformerException
{
int childCount = stepExpr.jjtGetNumChildren();
Node lastChild = stepExpr.jjtGetChild(childCount - 1);
if (lastChild instanceof Predicates)
{
if (lastChild.jjtGetNumChildren() > 0)
{
return true;
}
}
return false;
}
/**
* Analyze the location path and return 32 bits that give information about
* the location path as a whole. See the BIT_XXX constants for meaning about
* each of the bits.
*
* @param compiler non-null reference to compiler object that has processed
* the XPath operations into an opcode map.
* @param stepOpCodePos The opcode position for the step.
* @param stepIndex The top-level step index withing the iterator.
*
* @return 32 bits as an integer that give information about the location
* path as a whole.
*
* @throws javax.xml.transform.TransformerException
*/
private static int analyze(PathExpr pathExpr, int stepIndex)
throws javax.xml.transform.TransformerException
{
int numSteps = pathExpr.jjtGetNumChildren();
int analysisResult = 0x00000000; // 32 bits of analysis
for (int i = stepIndex; i < numSteps; i++)
{
StepExpr stepExpr = (StepExpr) pathExpr.jjtGetChild(i);
boolean predAnalysis = analyzePredicate(stepExpr);
if (predAnalysis)
analysisResult |= BIT_PREDICATE;
Node firstChild = stepExpr.jjtGetChild(0);
if (firstChild instanceof PatternAxis)
{
int axis = ((PatternAxis) firstChild).getAxis();
switch (axis)
{
case Axis.ROOT :
analysisResult |= BIT_ROOT;
break;
case Axis.DESCENDANTSORSELFFROMROOT :
case Axis.DESCENDANTSFROMROOT :
analysisResult |= (BIT_ROOT | BIT_ANY_DESCENDANT_FROM_ROOT);
break;
case Axis.ANCESTOR :
analysisResult |= BIT_ANCESTOR;
break;
case Axis.ANCESTORORSELF :
analysisResult |= BIT_ANCESTOR_OR_SELF;
break;
case Axis.ATTRIBUTE :
analysisResult |= BIT_ATTRIBUTE;
break;
case Axis.NAMESPACE :
analysisResult |= BIT_NAMESPACE;
break;
case Axis.CHILD :
analysisResult |= BIT_CHILD;
break;
case Axis.DESCENDANT :
analysisResult |= BIT_DESCENDANT;
break;
case Axis.DESCENDANTORSELF :
analysisResult |= BIT_DESCENDANT_OR_SELF;
break;
case Axis.FOLLOWING :
analysisResult |= BIT_FOLLOWING;
break;
case Axis.FOLLOWINGSIBLING :
analysisResult |= BIT_FOLLOWING_SIBLING;
break;
case Axis.PRECEDING :
analysisResult |= BIT_PRECEDING;
break;
case Axis.PRECEDINGSIBLING :
analysisResult |= BIT_PRECEDING_SIBLING;
break;
case Axis.PARENT :
analysisResult |= BIT_PARENT;
break;
case Axis.SELF :
analysisResult |= BIT_SELF;
break;
default :
// TBD: Change the wording of this expression.
throw new RuntimeException(
XSLMessages.createXPATHMessage(
XPATHErrorResources.ER_NULL_ERROR_HANDLER,
new Object[] { firstChild.getClass().getName()}));
//"Programmer's assertion: unknown opcode: "
//+ stepType);
}
Node secondChild = stepExpr.jjtGetChild(1);
if (secondChild instanceof org.apache.xpath.parser.NodeTest)
{
org.apache.xpath.parser.NodeTest nt =
(org.apache.xpath.parser.NodeTest) secondChild;
if (nt.getWhatToShow() == org.apache.xml.dtm.DTMFilter.SHOW_ALL)
{
analysisResult |= BIT_NODETEST_ANY;
}
}
}
else
{
analysisResult |= BIT_FILTER;
}
}
analysisResult |= (numSteps & BITS_COUNT);
return analysisResult;
}
/**
* Create a new LocPathIterator iterator. The exact type of iterator
* returned is based on an analysis of the XPath operations.
*
* @param compiler non-null reference to compiler object that has processed
* the XPath operations into an opcode map.
* @param opPos The position of the operation code for this itterator.
*
* @return non-null reference to a LocPathIterator or derivative.
*
* @throws javax.xml.transform.TransformerException
*/
public static DTMIterator newDTMIterator(
PathExpr pathExpr,
boolean isTopLevel)
throws javax.xml.transform.TransformerException
{
int analysis = analyze(pathExpr, 0);
boolean isOneStep = isOneStep(analysis);
DTMIterator iter = getPossibleUnion(pathExpr, isTopLevel, isOneStep);
if(null != iter)
return iter;
// Is the iteration a one-step attribute pattern (i.e. select="@foo")?
if (isOneStep
&& walksSelfOnly(analysis)
&& isWild(analysis)
&& !hasPredicate(analysis))
{
if (DEBUG_ITERATOR_CREATION)
diagnoseIterator("SelfIteratorNoPredicate", analysis, pathExpr);
// Then use a simple iteration of the attributes, with node test
// and predicate testing.
iter = new SelfIteratorNoPredicate();
}
// Is the iteration exactly one child step?
else
if (walksChildrenOnly(analysis) && isOneStep)
{
// Does the pattern specify *any* child with no predicate? (i.e. select="child::node()".
if (isWild(analysis) && !hasPredicate(analysis))
{
if (DEBUG_ITERATOR_CREATION)
diagnoseIterator("ChildIterator", analysis, pathExpr);
// Use simple child iteration without any test.
StepExpr stepExpr = (StepExpr) pathExpr.jjtGetChild(0);
iter = new ChildIterator(stepExpr, analysis);
}
else
{
if (DEBUG_ITERATOR_CREATION)
diagnoseIterator("ChildTestIterator", analysis, pathExpr);
// Else use simple node test iteration with predicate test.
StepExpr stepExpr = (StepExpr) pathExpr.jjtGetChild(0);
iter = new ChildTestIterator(stepExpr, analysis);
}
}
// Is the iteration a one-step attribute pattern (i.e. select="@foo")?
else
if (isOneStep && walksAttributes(analysis))
{
if (DEBUG_ITERATOR_CREATION)
diagnoseIterator("AttributeIterator", analysis, pathExpr);
// Then use a simple iteration of the attributes, with node test
// and predicate testing.
StepExpr stepExpr = (StepExpr) pathExpr.jjtGetChild(0);
iter = new AttributeIterator(stepExpr, analysis);
}
else
if (isOneStep && !walksFilteredList(analysis))
{
StepExpr stepExpr = (StepExpr) pathExpr.jjtGetChild(0);
if (!walksNamespaces(analysis)
&& (walksInDocOrder(analysis) || isSet(analysis, BIT_PARENT)))
{
if (false || DEBUG_ITERATOR_CREATION)
diagnoseIterator("OneStepIteratorForward", analysis, pathExpr);
// Then use a simple iteration of the attributes, with node test
// and predicate testing.
iter = new OneStepIteratorForward(stepExpr, analysis);
}
else
{
if (false || DEBUG_ITERATOR_CREATION)
diagnoseIterator("OneStepIterator", analysis, pathExpr);
// Then use a simple iteration of the attributes, with node test
// and predicate testing.
iter = new OneStepIterator(stepExpr, analysis);
}
}
// Analysis of "//center":
// bits: 1001000000001010000000000000011
// count: 3
// root
// child:node()
// BIT_DESCENDANT_OR_SELF
// It's highly possible that we should have a seperate bit set for
// "//foo" patterns.
// For at least the time being, we can't optimize patterns like
// "//table[3]", because this has to be analyzed as
// "/descendant-or-self::node()/table[3]" in order for the indexes
// to work right.
else
if (isOptimizableForDescendantIterator(pathExpr,
0) // && getStepCount(analysis) <= 3
// && walksDescendants(analysis)
// && walksSubtreeOnlyFromRootOrContext(analysis)
)
{
if (DEBUG_ITERATOR_CREATION)
diagnoseIterator("DescendantIterator", analysis, pathExpr);
StepExpr stepExpr;
if (pathExpr.jjtGetNumChildren() == 2)
{
stepExpr = (StepExpr) pathExpr.jjtGetChild(1);
PatternAxis axisExpr = stepExpr.getAxisExpr();
axisExpr.setAxis(org.apache.xml.dtm.Axis.DESCENDANTSFROMROOT);
}
else
stepExpr = (StepExpr) pathExpr.jjtGetChild(0);
iter = new DescendantIterator(stepExpr);
}
else
{
if (isNaturalDocOrder(pathExpr, 0, analysis))
{
if (false || DEBUG_ITERATOR_CREATION)
{
diagnoseIterator("WalkingIterator", analysis, pathExpr);
}
iter =
new WalkingIterator(
pathExpr.getParser().getPrefixResolver(),
pathExpr);
}
else
{
// if (DEBUG_ITERATOR_CREATION)
// diagnoseIterator("MatchPatternIterator", analysis, compiler);
//
// return new MatchPatternIterator(compiler, opPos, analysis);
if (DEBUG_ITERATOR_CREATION)
diagnoseIterator("WalkingIteratorSorted", analysis, pathExpr);
iter =
new WalkingIteratorSorted(
pathExpr.getParser().getPrefixResolver(),
pathExpr);
}
}
if (iter instanceof LocPathIterator)
((LocPathIterator) iter).setIsTopLevel(isTopLevel);
return iter;
}
/**
* Check to see if we have a UnionPathIterator contained by a
* StepExpr and possibly a predicate, contained in a PathExpr.
* If this is the case, we just want the UnionPathIterator and
* any predicates it may have.
* It's likely that this reduction should be done somewhere else.
*
* @param pathExpr The path construction node that holds the subtree.
* @param isTopLevel True if this expression is at the top-level.
* @param isOneStep True if this expression only has one step.
* @return DTMIterator The reduced union iterator, or null if not a union.
* @throws TransformerException
*/
private static DTMIterator getPossibleUnion(
PathExpr pathExpr,
boolean isTopLevel,
boolean isOneStep)
throws TransformerException
{
Node n;
if(isOneStep &&
(n = pathExpr.jjtGetChild(0).jjtGetChild(0)) instanceof UnionPathIterator)
{
UnionPathIterator upi = (UnionPathIterator)n;
StepExpr se = (StepExpr)pathExpr.jjtGetChild(0);
upi.initPredicateInfo(se);
upi.setWhatToShow(DTMFilter.SHOW_ALL);
upi.setIsTopLevel(isTopLevel);
return upi;
}
else
return null;
}
public static void diagnoseIterator(
String name,
int analysis,
PathExpr pathExpr)
{
System.out.println(
pathExpr.toString()
+ ", "
+ name
+ ", "
+ Integer.toBinaryString(analysis)
+ ", "
+ getAnalysisString(analysis));
}
public static String getAnalysisString(int analysis)
{
StringBuffer buf = new StringBuffer();
buf.append("count: " + getStepCount(analysis) + " ");
if ((analysis & BIT_NODETEST_ANY) != 0)
{
buf.append("NTANY|");
}
if ((analysis & BIT_PREDICATE) != 0)
{
buf.append("PRED|");
}
if ((analysis & BIT_ANCESTOR) != 0)
{
buf.append("ANC|");
}
if ((analysis & BIT_ANCESTOR_OR_SELF) != 0)
{
buf.append("ANCOS|");
}
if ((analysis & BIT_ATTRIBUTE) != 0)
{
buf.append("ATTR|");
}
if ((analysis & BIT_CHILD) != 0)
{
buf.append("CH|");
}
if ((analysis & BIT_DESCENDANT) != 0)
{
buf.append("DESC|");
}
if ((analysis & BIT_DESCENDANT_OR_SELF) != 0)
{
buf.append("DESCOS|");
}
if ((analysis & BIT_FOLLOWING) != 0)
{
buf.append("FOL|");
}
if ((analysis & BIT_FOLLOWING_SIBLING) != 0)
{
buf.append("FOLS|");
}
if ((analysis & BIT_NAMESPACE) != 0)
{
buf.append("NS|");
}
if ((analysis & BIT_PARENT) != 0)
{
buf.append("P|");
}
if ((analysis & BIT_PRECEDING) != 0)
{
buf.append("PREC|");
}
if ((analysis & BIT_PRECEDING_SIBLING) != 0)
{
buf.append("PRECS|");
}
if ((analysis & BIT_SELF) != 0)
{
buf.append(".|");
}
if ((analysis & BIT_FILTER) != 0)
{
buf.append("FLT|");
}
if ((analysis & BIT_ROOT) != 0)
{
buf.append("R|");
}
return buf.toString();
}
/** Set to true for diagnostics about walker creation */
static final boolean DEBUG_PATTERN_CREATION = false;
/** Set to true for diagnostics about walker creation */
static final boolean DEBUG_WALKER_CREATION = false;
/** Set to true for diagnostics about iterator creation */
static final boolean DEBUG_ITERATOR_CREATION = false;
public static boolean hasPredicate(int analysis)
{
return (0 != (analysis & BIT_PREDICATE));
}
public static boolean isWild(int analysis)
{
return (0 != (analysis & BIT_NODETEST_ANY));
}
public static boolean walksAncestors(int analysis)
{
return isSet(analysis, BIT_ANCESTOR | BIT_ANCESTOR_OR_SELF);
}
public static boolean walksAttributes(int analysis)
{
return (0 != (analysis & BIT_ATTRIBUTE));
}
public static boolean walksNamespaces(int analysis)
{
return (0 != (analysis & BIT_NAMESPACE));
}
public static boolean walksChildren(int analysis)
{
return (0 != (analysis & BIT_CHILD));
}
public static boolean walksDescendants(int analysis)
{
return isSet(analysis, BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF | BIT_ANY_DESCENDANT_FROM_ROOT);
}
public static boolean walksSubtree(int analysis)
{
return isSet(analysis, BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF | BIT_CHILD);
}
public static boolean walksSubtreeOnlyMaybeAbsolute(int analysis)
{
return walksSubtree(analysis)
&& !walksExtraNodes(analysis)
&& !walksUp(analysis)
&& !walksSideways(analysis);
}
public static boolean walksSubtreeOnly(int analysis)
{
return walksSubtreeOnlyMaybeAbsolute(analysis) && !isAbsolute(analysis);
}
public static boolean walksFilteredList(int analysis)
{
return isSet(analysis, BIT_FILTER);
}
public static boolean walksSubtreeOnlyFromRootOrContext(int analysis)
{
return walksSubtree(analysis)
&& !walksExtraNodes(analysis)
&& !walksUp(analysis)
&& !walksSideways(analysis)
&& !isSet(analysis, BIT_FILTER);
}
public static boolean walksInDocOrder(int analysis)
{
return (
walksSubtreeOnlyMaybeAbsolute(analysis)
|| walksExtraNodesOnly(analysis)
|| walksFollowingOnlyMaybeAbsolute(analysis))
&& !isSet(analysis, BIT_FILTER);
}
public static boolean walksFollowingOnlyMaybeAbsolute(int analysis)
{
return isSet(analysis, BIT_SELF | BIT_FOLLOWING_SIBLING | BIT_FOLLOWING)
&& !walksSubtree(analysis)
&& !walksUp(analysis)
&& !walksSideways(analysis);
}
public static boolean walksUp(int analysis)
{
return isSet(analysis, BIT_PARENT | BIT_ANCESTOR | BIT_ANCESTOR_OR_SELF);
}
public static boolean walksSideways(int analysis)
{
return isSet(
analysis,
BIT_FOLLOWING
| BIT_FOLLOWING_SIBLING
| BIT_PRECEDING
| BIT_PRECEDING_SIBLING);
}
public static boolean walksExtraNodes(int analysis)
{
return isSet(analysis, BIT_NAMESPACE | BIT_ATTRIBUTE);
}
public static boolean walksExtraNodesOnly(int analysis)
{
return walksExtraNodes(analysis)
&& !isSet(analysis, BIT_SELF)
&& !walksSubtree(analysis)
&& !walksUp(analysis)
&& !walksSideways(analysis)
&& !isAbsolute(analysis);
}
public static boolean isAbsolute(int analysis)
{
return isSet(analysis, BIT_ROOT | BIT_FILTER);
}
public static boolean walksChildrenOnly(int analysis)
{
return walksChildren(analysis)
&& !isSet(analysis, BIT_SELF)
&& !walksExtraNodes(analysis)
&& !walksDescendants(analysis)
&& !walksUp(analysis)
&& !walksSideways(analysis)
&& (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT));
}
public static boolean walksChildrenAndExtraAndSelfOnly(int analysis)
{
return walksChildren(analysis)
&& !walksDescendants(analysis)
&& !walksUp(analysis)
&& !walksSideways(analysis)
&& (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT));
}
public static boolean walksDescendantsAndExtraAndSelfOnly(int analysis)
{
return !walksChildren(analysis)
&& walksDescendants(analysis)
&& !walksUp(analysis)
&& !walksSideways(analysis)
&& (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT));
}
public static boolean walksSelfOnly(int analysis)
{
return isSet(analysis, BIT_SELF)
&& !walksSubtree(analysis)
&& !walksUp(analysis)
&& !walksSideways(analysis)
&& !isAbsolute(analysis);
}
public static boolean walksUpOnly(int analysis)
{
return !walksSubtree(analysis)
&& walksUp(analysis)
&& !walksSideways(analysis)
&& !isAbsolute(analysis);
}
public static boolean walksDownOnly(int analysis)
{
return walksSubtree(analysis)
&& !walksUp(analysis)
&& !walksSideways(analysis)
&& !isAbsolute(analysis);
}
public static boolean walksDownExtraOnly(int analysis)
{
return walksSubtree(analysis)
&& walksExtraNodes(analysis)
&& !walksUp(analysis)
&& !walksSideways(analysis)
&& !isAbsolute(analysis);
}
public static boolean canSkipSubtrees(int analysis)
{
return isSet(analysis, BIT_CHILD) | walksSideways(analysis);
}
public static boolean canCrissCross(int analysis)
{
// This could be done faster. Coded for clarity.
if (walksSelfOnly(analysis))
return false;
else
if (walksDownOnly(analysis) && !canSkipSubtrees(analysis))
return false;
else
if (walksChildrenAndExtraAndSelfOnly(analysis))
return false;
else
if (walksDescendantsAndExtraAndSelfOnly(analysis))
return false;
else
if (walksUpOnly(analysis))
return false;
else
if (walksExtraNodesOnly(analysis))
return false;
else
if (walksSubtree(analysis)
&& (walksSideways(analysis)
|| walksUp(analysis)
|| canSkipSubtrees(analysis)))
return true;
else
return false;
}
/**
* Tell if the pattern can be 'walked' with the iteration steps in natural
* document order, without duplicates.
*
* @param analysis The general analysis of the pattern.
*
* @return true if the walk can be done in natural order.
*
* @throws javax.xml.transform.TransformerException
*/
static public boolean isNaturalDocOrder(int analysis)
{
if (canCrissCross(analysis)
|| isSet(analysis, BIT_NAMESPACE)
|| walksFilteredList(analysis))
return false;
if (walksInDocOrder(analysis))
return true;
return false;
}
public static boolean isOneStep(int analysis)
{
return (analysis & BITS_COUNT) == 0x00000001;
}
public static int getStepCount(int analysis)
{
return (analysis & BITS_COUNT);
}
/**
* Tell if the pattern can be 'walked' with the iteration steps in natural
* document order, without duplicates.
*
* @param pathExpr Root of the path expression being analyzed.
* @param stepIndex The top-level step index withing the iterator.
* @param analysis The general analysis of the pattern.
*
* @return true if the walk can be done in natural order.
*
* @throws javax.xml.transform.TransformerException
*/
private static boolean isNaturalDocOrder(
PathExpr pathExpr,
int stepIndex,
int analysis)
throws javax.xml.transform.TransformerException
{
if (canCrissCross(analysis))
return false;
// Namespaces can present some problems, so just punt if we're looking for
// these.
if (isSet(analysis, BIT_NAMESPACE))
return false;
// The following, preceding, following-sibling, and preceding sibling can
// be found in doc order if we get to this point, but if they occur
// together, they produce
// duplicates, so it's better for us to eliminate this case so we don't
// have to check for duplicates during runtime if we're using a
// WalkingIterator.
if (isSet(analysis, BIT_FOLLOWING | BIT_FOLLOWING_SIBLING)
&& isSet(analysis, BIT_PRECEDING | BIT_PRECEDING_SIBLING))
return false;
// OK, now we have to check for select="@*/axis::*" patterns, which
// can also cause duplicates to happen. But select="axis*/@::*" patterns
// are OK, as are select="@foo/axis::*" patterns.
// Unfortunately, we can't do this just via the analysis bits.
int stepType;
boolean foundWildAttribute = false;
// Steps that can traverse anything other than down a
// subtree or that can produce duplicates when used in
// combonation are counted with this variable.
int potentialDuplicateMakingStepCount = 0;
int numSteps = pathExpr.jjtGetNumChildren();
for (int i = 0; i < numSteps; i++)
{
StepExpr stepExpr = (StepExpr) pathExpr.jjtGetChild(stepIndex);
Node firstChild = stepExpr.jjtGetChild(0);
if (firstChild instanceof PatternAxis)
{
Node secondChild = stepExpr.jjtGetChild(1);
org.apache.xpath.parser.NodeTest nt;
boolean isTotallyWild;
if (secondChild instanceof org.apache.xpath.parser.NodeTest)
{
nt = (org.apache.xpath.parser.NodeTest) secondChild;
isTotallyWild = nt.isTotallyWild();
// Double check.
if (0
!= (nt.getWhatToShow() | org.apache.xml.dtm.DTMFilter.SHOW_ALL))
{
isTotallyWild = true;
}
}
else
{
isTotallyWild = false;
nt = null;
}
int axis = ((PatternAxis) firstChild).getAxis();
switch (axis)
{
case Axis.NAMESPACE :
case Axis.ATTRIBUTE :
if (foundWildAttribute) // Maybe not needed, but be safe.
return false;
if (isTotallyWild)
foundWildAttribute = true;
break;
case Axis.DESCENDANTSFROMROOT :
case Axis.DESCENDANTSORSELFFROMROOT :
case Axis.ANCESTOR :
case Axis.ANCESTORORSELF :
case Axis.DESCENDANT :
case Axis.DESCENDANTORSELF :
case Axis.FOLLOWING :
case Axis.FOLLOWINGSIBLING :
case Axis.PRECEDING :
case Axis.PRECEDINGSIBLING :
case Axis.PARENT :
if (potentialDuplicateMakingStepCount > 0)
return false;
potentialDuplicateMakingStepCount++;
case Axis.ROOT :
case Axis.CHILD :
case Axis.SELF :
if (foundWildAttribute)
return false;
break;
default :
// TBD: Change the wording of this expression.
throw new RuntimeException(
XSLMessages.createXPATHMessage(
XPATHErrorResources.ER_NULL_ERROR_HANDLER,
new Object[] { firstChild.getClass().getName()}));
//"Programmer's assertion: unknown opcode: "
//+ stepType);
}
}
else
{
// For the moment return false if it is a filter expression.
// Ideally, we'd like to follow the analysis into a variable or function.
return false;
}
}
return true;
}
/**
* Special purpose function to see if we can optimize the pattern for
* a DescendantIterator.
*
* @param pathExpr Root of the path expression being analyzed.
* @param stepIndex The top-level step index withing the iterator.
*
* @return 32 bits as an integer that give information about the location
* path as a whole.
*
* @throws javax.xml.transform.TransformerException
*/
private static boolean isOptimizableForDescendantIterator(
PathExpr pathExpr,
int stepIndex)
throws javax.xml.transform.TransformerException
{
int stepType;
boolean foundDESCENDANTSFROMROOT = false;
int nodeTestType = DTMFilter.SHOW_ALL;
int numSteps = pathExpr.jjtGetNumChildren();
if (numSteps > 2)
return false;
for (int i = 0; i < numSteps; i++)
{
StepExpr stepExpr = (StepExpr) pathExpr.jjtGetChild(i);
int axis = stepExpr.getAxis();
switch (axis)
{
case Axis.SELF :
case Axis.ATTRIBUTE :
case Axis.ROOT :
case Axis.ANCESTOR :
case Axis.ANCESTORORSELF :
case Axis.NAMESPACE :
case Axis.DESCENDANT :
case Axis.DESCENDANTORSELF :
case Axis.FOLLOWING :
case Axis.FOLLOWINGSIBLING :
case Axis.PRECEDING :
case Axis.PRECEDINGSIBLING :
case Axis.PARENT :
return false;
case Axis.DESCENDANTSORSELFFROMROOT :
case Axis.DESCENDANTSFROMROOT :
if (0 != i)
return false;
foundDESCENDANTSFROMROOT = true;
if (analyzePredicate(stepExpr))
{
return false;
}
break;
case Axis.CHILD :
if (!foundDESCENDANTSFROMROOT || 1 != i)
return false;
if(mightBeProximate(stepExpr))
return false;
break;
default :
return false;
// TBD: Change the wording of this expression.
// throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{firstChild.getClass().getName()})); //"Programmer's assertion: unknown opcode: "
}
// TBD: I don't think the code will function properly without this.
// boolean mightBeProximate = mightBeProximate(compiler, stepOpCodePos, stepType);
// if(mightBeProximate)
// return false;
}
return true;
}
// TBD: Needs to use methods on the expressions instead of instanceof!
/**
* Tell if the predicates need to have proximity knowledge.
*/
public static boolean mightBeProximate(Expression stepExpr)
throws javax.xml.transform.TransformerException
{
boolean mightBeProximate = false;
int argLen;
Node lastChild = stepExpr.jjtGetChild(stepExpr.jjtGetNumChildren() - 1);
if (lastChild instanceof Predicates)
{
Predicates preds = (Predicates) lastChild;
int numChildren = preds.jjtGetNumChildren();
for (int i = 0; i < numChildren; i++)
{
Expression expr = (Expression) preds.jjtGetChild(i);
if (expr instanceof org.apache.xpath.operations.Variable)
{
return true;
// Would need more smarts to tell if this could be a number or not!
}
else
if (expr instanceof org.apache.xpath.objects.XNumber)
{
return true;
}
else
if (expr instanceof org.apache.xpath.parser.PathExpr
|| expr instanceof LocPathIterator)
{
// OK, keep going, we don't want to recurse.
}
else
if (expr instanceof org.apache.xpath.functions.Function)
{
boolean isProx =
functionProximateOrContainsProximate(
(org.apache.xpath.functions.Function) expr);
if (isProx)
return true;
break;
}
else
{
int numChildrenOfExpr = expr.jjtGetNumChildren();
for (int j = 0; j < numChildrenOfExpr; j++)
{
Expression exprChild = (Expression) expr.jjtGetChild(j);
boolean prox = isProximateInnerExpr(exprChild);
if (prox)
return true;
}
}
}
}
return mightBeProximate;
}
// TBD: Needs to use methods on the expressions instead of instanceof!
static boolean functionProximateOrContainsProximate(
org.apache.xpath.functions.Function func)
{
if (func instanceof org.apache.xpath.functions.FuncLast
|| func instanceof org.apache.xpath.functions.FuncPosition)
{
return true;
}
else
{
int numChildren = func.jjtGetNumChildren();
for (int i = 0; i < numChildren; i++)
{
Expression expr = (Expression) func.jjtGetChild(i);
boolean prox = isProximateInnerExpr(expr);
if (prox)
return true;
}
}
return false;
}
// TBD: Needs to use methods on the expressions instead of instanceof!
static boolean isProximateInnerExpr(Expression expr)
{
boolean mightBeProximate = false;
int argLen;
if (expr instanceof org.apache.xpath.parser.PathExpr
|| expr instanceof LocPathIterator)
{
// OK, we don't want to recurse!
}
else
if (expr instanceof org.apache.xpath.functions.Function)
{
boolean isProx =
functionProximateOrContainsProximate(
(org.apache.xpath.functions.Function) expr);
if (isProx)
return true;
}
else
{
int numChildrenOfExpr = expr.jjtGetNumChildren();
for (int j = 0; j < numChildrenOfExpr; j++)
{
Expression exprChild = (Expression) expr.jjtGetChild(j);
boolean prox = isProximateInnerExpr(exprChild);
if (prox)
return true;
}
}
return mightBeProximate;
}
/**
* Create the proper Walker from the axes type.
*
* @param compiler non-null reference to compiler object that has processed
* the XPath operations into an opcode map.
* @param opPos The opcode position for the step.
* @param lpi The owning location path iterator.
* @param analysis 32 bits of analysis, from which the type of AxesWalker
* may be influenced.
*
* @return non-null reference to AxesWalker derivative.
* @throws RuntimeException if the input is bad.
*/
private static AxesWalker createDefaultWalker(
StepExpr stepExpr,
WalkingIterator lpi,
int analysis)
{
AxesWalker ai = null;
PatternAxis patternAxis = stepExpr.getAxisExpr();
if (null != patternAxis)
{
boolean isTotallyWild = stepExpr.isTotallyWild();
int axis = stepExpr.getAxis();
switch (axis)
{
case Axis.ROOT :
ai = new AxesWalker(lpi, Axis.ROOT);
break;
case Axis.DESCENDANTSFROMROOT :
ai = new AxesWalker(lpi, Axis.DESCENDANTSFROMROOT);
break;
case Axis.DESCENDANTSORSELFFROMROOT :
ai = new AxesWalker(lpi, Axis.DESCENDANTSORSELFFROMROOT);
break;
case Axis.ANCESTOR :
ai = new ReverseAxesWalker(lpi, Axis.ANCESTOR);
break;
case Axis.ANCESTORORSELF :
ai = new ReverseAxesWalker(lpi, Axis.ANCESTORORSELF);
break;
case Axis.ATTRIBUTE :
ai = new AxesWalker(lpi, Axis.ATTRIBUTE);
break;
case Axis.NAMESPACE :
ai = new AxesWalker(lpi, Axis.NAMESPACE);
break;
case Axis.CHILD :
ai = new AxesWalker(lpi, Axis.CHILD);
break;
case Axis.DESCENDANT :
ai = new AxesWalker(lpi, Axis.DESCENDANT);
break;
case Axis.DESCENDANTORSELF :
ai = new AxesWalker(lpi, Axis.DESCENDANTORSELF);
break;
case Axis.FOLLOWING :
ai = new AxesWalker(lpi, Axis.FOLLOWING);
break;
case Axis.FOLLOWINGSIBLING :
ai = new AxesWalker(lpi, Axis.FOLLOWINGSIBLING);
break;
case Axis.PRECEDING :
ai = new ReverseAxesWalker(lpi, Axis.PRECEDING);
break;
case Axis.PRECEDINGSIBLING :
ai = new ReverseAxesWalker(lpi, Axis.PRECEDINGSIBLING);
break;
case Axis.PARENT :
ai = new ReverseAxesWalker(lpi, Axis.PARENT);
break;
case Axis.SELF :
ai = new AxesWalker(lpi, Axis.SELF);
break;
default :
throw new RuntimeException(
XSLMessages.createXPATHMessage(
XPATHErrorResources.ER_NULL_ERROR_HANDLER,
new Object[] { StepExpr.class.getName()}));
//"Programmer's assertion: unknown opcode: "
//+ stepType);
}
int whatToShow = stepExpr.getWhatToShow();
/*
System.out.print("construct: ");
NodeTest.debugWhatToShow(whatToShow);
System.out.println("or stuff: "+(whatToShow & (DTMFilter.SHOW_ATTRIBUTE
| DTMFilter.SHOW_ELEMENT
| DTMFilter.SHOW_PROCESSING_INSTRUCTION)));
*/
if ((0
== (whatToShow
& (DTMFilter.SHOW_ATTRIBUTE
| DTMFilter.SHOW_NAMESPACE
| DTMFilter.SHOW_ELEMENT
| DTMFilter.SHOW_PROCESSING_INSTRUCTION)))
|| (whatToShow == DTMFilter.SHOW_ALL))
ai.initNodeTest(whatToShow);
else
{
ai.initNodeTest(
whatToShow,
stepExpr.getNamespaceURI(),
stepExpr.getLocalName());
}
}
else
{
// FilterWalker
if (DEBUG_WALKER_CREATION)
System.out.println(
"new walker: FilterExprWalker: "
+ analysis
+ ", "
+ stepExpr.toString());
ai = new FilterExprWalker(lpi);
try
{
ai.init(stepExpr);
}
catch (TransformerException te)
{
throw new org.apache.xml.utils.WrappedRuntimeException(te);
}
ai.initNodeTest(DTMFilter.SHOW_ALL);
}
return ai;
}
/**
* <meta name="usage" content="advanced"/>
* This method is for building an array of possible levels
* where the target element(s) could be found for a match.
* @param xpath The xpath that is executing.
* @param context The current source tree context node.
*
* @param lpi The owning location path iterator object.
* @param compiler non-null reference to compiler object that has processed
* the XPath operations into an opcode map.
* @param stepOpCodePos The opcode position for the step.
* @param stepIndex The top-level step index withing the iterator.
*
* @return non-null AxesWalker derivative.
*
* @throws javax.xml.transform.TransformerException
*/
static AxesWalker loadWalkers(
org.apache.xpath.parser.PathExpr pathExpr,
WalkingIterator lpi)
throws javax.xml.transform.TransformerException
{
int stepType;
AxesWalker firstWalker = null;
AxesWalker walker, prevWalker = null;
int analysis = analyze(pathExpr, 0);
int numSteps = pathExpr.jjtGetNumChildren();
for (int i = 0; i < numSteps; i++)
{
StepExpr stepExpr = (StepExpr) pathExpr.jjtGetChild(i);
walker = createDefaultWalker(stepExpr, lpi, analysis);
walker.init(stepExpr);
// walker.setAnalysis(analysis);
if (null == firstWalker)
{
firstWalker = walker;
walker.exprSetParent(lpi);
}
else
{
prevWalker.setNextWalker(walker);
walker.setPrevWalker(prevWalker);
walker.exprSetParent(prevWalker);
}
prevWalker = walker;
}
return firstWalker;
}
}
//import org.apache.xpath.compiler.OpCodes;
//import org.apache.xpath.compiler.Compiler;
//import org.apache.xpath.compiler.FunctionTable;
//import org.apache.xpath.patterns.NodeTest;
//import org.apache.xpath.patterns.StepPattern;
//import org.apache.xpath.patterns.ContextMatchStepPattern;
//import org.apache.xpath.patterns.FunctionPattern;
//import org.apache.xpath.Expression;
//import org.apache.xpath.objects.XNumber;
//import org.apache.xalan.res.XSLMessages;
//import org.apache.xpath.res.XPATHErrorResources;
//
//import org.apache.xml.dtm.DTMFilter;
//import org.apache.xml.dtm.DTMIterator;
//import org.apache.xml.dtm.Axis;
//
///**
// * This class is both a factory for XPath location path expressions,
// * which are built from the opcode map output, and an analysis engine
// * for the location path expressions in order to provide optimization hints.
// */
//public class WalkerFactory
//{
//
// /**
// * <meta name="usage" content="advanced"/>
// * This method is for building an array of possible levels
// * where the target element(s) could be found for a match.
// * @param xpath The xpath that is executing.
// * @param context The current source tree context node.
// *
// * @param lpi The owning location path iterator.
// * @param compiler non-null reference to compiler object that has processed
// * the XPath operations into an opcode map.
// * @param stepOpCodePos The opcode position for the step.
// *
// * @return non-null AxesWalker derivative.
// *
// * @throws javax.xml.transform.TransformerException
// */
// static AxesWalker loadOneWalker(
// WalkingIterator lpi, Compiler compiler, int stepOpCodePos)
// throws javax.xml.transform.TransformerException
// {
//
// AxesWalker firstWalker = null;
// int stepType = compiler.getOpMap()[stepOpCodePos];
//
// if (stepType != OpCodes.ENDOP)
// {
//
// // m_axesWalkers = new AxesWalker[1];
// // As we unwind from the recursion, create the iterators.
// firstWalker = createDefaultWalker(compiler, stepType, lpi, 0);
//
// firstWalker.init(compiler, stepOpCodePos, stepType);
// }
//
// return firstWalker;
// }
//
// /**
// * <meta name="usage" content="advanced"/>
// * This method is for building an array of possible levels
// * where the target element(s) could be found for a match.
// * @param xpath The xpath that is executing.
// * @param context The current source tree context node.
// *
// * @param lpi The owning location path iterator object.
// * @param compiler non-null reference to compiler object that has processed
// * the XPath operations into an opcode map.
// * @param stepOpCodePos The opcode position for the step.
// * @param stepIndex The top-level step index withing the iterator.
// *
// * @return non-null AxesWalker derivative.
// *
// * @throws javax.xml.transform.TransformerException
// */
// static AxesWalker loadWalkers(
// WalkingIterator lpi, Compiler compiler, int stepOpCodePos, int stepIndex)
// throws javax.xml.transform.TransformerException
// {
//
// int stepType;
// AxesWalker firstWalker = null;
// AxesWalker walker, prevWalker = null;
// int ops[] = compiler.getOpMap();
// int analysis = analyze(compiler, stepOpCodePos, stepIndex);
//
// while (OpCodes.ENDOP != (stepType = ops[stepOpCodePos]))
// {
// walker = createDefaultWalker(compiler, stepOpCodePos, lpi, analysis);
//
// walker.init(compiler, stepOpCodePos, stepType);
// walker.exprSetParent(lpi);
//
// // walker.setAnalysis(analysis);
// if (null == firstWalker)
// {
// firstWalker = walker;
// }
// else
// {
// prevWalker.setNextWalker(walker);
// walker.setPrevWalker(prevWalker);
// }
//
// prevWalker = walker;
// stepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
//
// if (stepOpCodePos < 0)
// break;
// }
//
// return firstWalker;
// }
//
// public static boolean isSet(int analysis, int bits)
// {
// return (0 != (analysis & bits));
// }
//
// public static void diagnoseIterator(String name, int analysis, Compiler compiler)
// {
// System.out.println(compiler.toString()+", "+name+", "
// + Integer.toBinaryString(analysis) + ", "
// + getAnalysisString(analysis));
// }
//
// /**
// * Create a new LocPathIterator iterator. The exact type of iterator
// * returned is based on an analysis of the XPath operations.
// *
// * @param compiler non-null reference to compiler object that has processed
// * the XPath operations into an opcode map.
// * @param opPos The position of the operation code for this itterator.
// *
// * @return non-null reference to a LocPathIterator or derivative.
// *
// * @throws javax.xml.transform.TransformerException
// */
// public static DTMIterator newDTMIterator(
// Compiler compiler, int opPos,
// boolean isTopLevel)
// throws javax.xml.transform.TransformerException
// {
//
// int firstStepPos = compiler.getFirstChildPos(opPos);
// int analysis = analyze(compiler, firstStepPos, 0);
// boolean isOneStep = isOneStep(analysis);
// DTMIterator iter;
//
// // Is the iteration a one-step attribute pattern (i.e. select="@foo")?
// if (isOneStep && walksSelfOnly(analysis) &&
// isWild(analysis) && !hasPredicate(analysis))
// {
// if (DEBUG_ITERATOR_CREATION)
// diagnoseIterator("SelfIteratorNoPredicate", analysis, compiler);
//
// // Then use a simple iteration of the attributes, with node test
// // and predicate testing.
// iter = new SelfIteratorNoPredicate(compiler, opPos, analysis);
// }
// // Is the iteration exactly one child step?
// else if (walksChildrenOnly(analysis) && isOneStep)
// {
//
// // Does the pattern specify *any* child with no predicate? (i.e. select="child::node()".
// if (isWild(analysis) && !hasPredicate(analysis))
// {
// if (DEBUG_ITERATOR_CREATION)
// diagnoseIterator("ChildIterator", analysis, compiler);
//
// // Use simple child iteration without any test.
// iter = new ChildIterator(compiler, opPos, analysis);
// }
// else
// {
// if (DEBUG_ITERATOR_CREATION)
// diagnoseIterator("ChildTestIterator", analysis, compiler);
//
// // Else use simple node test iteration with predicate test.
// iter = new ChildTestIterator(compiler, opPos, analysis);
// }
// }
// // Is the iteration a one-step attribute pattern (i.e. select="@foo")?
// else if (isOneStep && walksAttributes(analysis))
// {
// if (DEBUG_ITERATOR_CREATION)
// diagnoseIterator("AttributeIterator", analysis, compiler);
//
// // Then use a simple iteration of the attributes, with node test
// // and predicate testing.
// iter = new AttributeIterator(compiler, opPos, analysis);
// }
// else if(isOneStep && !walksFilteredList(analysis))
// {
// if( !walksNamespaces(analysis)
// && (walksInDocOrder(analysis) || isSet(analysis, BIT_PARENT)))
// {
// if (false || DEBUG_ITERATOR_CREATION)
// diagnoseIterator("OneStepIteratorForward", analysis, compiler);
//
// // Then use a simple iteration of the attributes, with node test
// // and predicate testing.
// iter = new OneStepIteratorForward(compiler, opPos, analysis);
// }
// else
// {
// if (false || DEBUG_ITERATOR_CREATION)
// diagnoseIterator("OneStepIterator", analysis, compiler);
//
// // Then use a simple iteration of the attributes, with node test
// // and predicate testing.
// iter = new OneStepIterator(compiler, opPos, analysis);
// }
// }
//
// // Analysis of "//center":
// // bits: 1001000000001010000000000000011
// // count: 3
// // root
// // child:node()
// // BIT_DESCENDANT_OR_SELF
// // It's highly possible that we should have a seperate bit set for
// // "//foo" patterns.
// // For at least the time being, we can't optimize patterns like
// // "//table[3]", because this has to be analyzed as
// // "/descendant-or-self::node()/table[3]" in order for the indexes
// // to work right.
// else if (isOptimizableForDescendantIterator(compiler, firstStepPos, 0)
// // && getStepCount(analysis) <= 3
// // && walksDescendants(analysis)
// // && walksSubtreeOnlyFromRootOrContext(analysis)
// )
// {
// if (DEBUG_ITERATOR_CREATION)
// diagnoseIterator("DescendantIterator", analysis, compiler);
//
// iter = new DescendantIterator(compiler, opPos, analysis);
// }
// else
// {
// if(isNaturalDocOrder(compiler, firstStepPos, 0, analysis))
// {
// if (false || DEBUG_ITERATOR_CREATION)
// {
// diagnoseIterator("WalkingIterator", analysis, compiler);
// }
//
// iter = new WalkingIterator(compiler, opPos, analysis, true);
// }
// else
// {
//// if (DEBUG_ITERATOR_CREATION)
//// diagnoseIterator("MatchPatternIterator", analysis, compiler);
////
//// return new MatchPatternIterator(compiler, opPos, analysis);
// if (DEBUG_ITERATOR_CREATION)
// diagnoseIterator("WalkingIteratorSorted", analysis, compiler);
//
// iter = new WalkingIteratorSorted(compiler, opPos, analysis, true);
// }
// }
// if(iter instanceof LocPathIterator)
// ((LocPathIterator)iter).setIsTopLevel(isTopLevel);
//
// return iter;
// }
//
// /**
// * Special purpose function to see if we can optimize the pattern for
// * a DescendantIterator.
// *
// * @param compiler non-null reference to compiler object that has processed
// * the XPath operations into an opcode map.
// * @param stepOpCodePos The opcode position for the step.
// * @param stepIndex The top-level step index withing the iterator.
// *
// * @return 32 bits as an integer that give information about the location
// * path as a whole.
// *
// * @throws javax.xml.transform.TransformerException
// */
// public static int getAxisFromStep(
// Compiler compiler, int stepOpCodePos)
// throws javax.xml.transform.TransformerException
// {
//
// int ops[] = compiler.getOpMap();
// int stepType = ops[stepOpCodePos];
//
// switch (stepType)
// {
// case OpCodes.FROM_FOLLOWING :
// return Axis.FOLLOWING;
// case OpCodes.FROM_FOLLOWING_SIBLINGS :
// return Axis.FOLLOWINGSIBLING;
// case OpCodes.FROM_PRECEDING :
// return Axis.PRECEDING;
// case OpCodes.FROM_PRECEDING_SIBLINGS :
// return Axis.PRECEDINGSIBLING;
// case OpCodes.FROM_PARENT :
// return Axis.PARENT;
// case OpCodes.FROM_NAMESPACE :
// return Axis.NAMESPACE;
// case OpCodes.FROM_ANCESTORS :
// return Axis.ANCESTOR;
// case OpCodes.FROM_ANCESTORS_OR_SELF :
// return Axis.ANCESTORORSELF;
// case OpCodes.FROM_ATTRIBUTES :
// return Axis.ATTRIBUTE;
// case OpCodes.FROM_ROOT :
// return Axis.ROOT;
// case OpCodes.FROM_CHILDREN :
// return Axis.CHILD;
// case OpCodes.FROM_DESCENDANTS_OR_SELF :
// return Axis.DESCENDANTORSELF;
// case OpCodes.FROM_DESCENDANTS :
// return Axis.DESCENDANT;
// case OpCodes.FROM_SELF :
// return Axis.SELF;
// case OpCodes.OP_EXTFUNCTION :
// case OpCodes.OP_FUNCTION :
// case OpCodes.OP_GROUP :
// case OpCodes.OP_VARIABLE :
// return Axis.FILTEREDLIST;
// }
//
// throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
// //+ stepType);
// }
//
// /**
// * Get a corresponding BIT_XXX from an axis.
// * @param axis One of Axis.ANCESTOR, etc.
// * @return One of BIT_ANCESTOR, etc.
// */
// static public int getAnalysisBitFromAxes(int axis)
// {
// switch (axis) // Generate new traverser
// {
// case Axis.ANCESTOR :
// return BIT_ANCESTOR;
// case Axis.ANCESTORORSELF :
// return BIT_ANCESTOR_OR_SELF;
// case Axis.ATTRIBUTE :
// return BIT_ATTRIBUTE;
// case Axis.CHILD :
// return BIT_CHILD;
// case Axis.DESCENDANT :
// return BIT_DESCENDANT;
// case Axis.DESCENDANTORSELF :
// return BIT_DESCENDANT_OR_SELF;
// case Axis.FOLLOWING :
// return BIT_FOLLOWING;
// case Axis.FOLLOWINGSIBLING :
// return BIT_FOLLOWING_SIBLING;
// case Axis.NAMESPACE :
// case Axis.NAMESPACEDECLS :
// return BIT_NAMESPACE;
// case Axis.PARENT :
// return BIT_PARENT;
// case Axis.PRECEDING :
// return BIT_PRECEDING;
// case Axis.PRECEDINGSIBLING :
// return BIT_PRECEDING_SIBLING;
// case Axis.SELF :
// return BIT_SELF;
// case Axis.ALLFROMNODE :
// return BIT_DESCENDANT_OR_SELF;
// // case Axis.PRECEDINGANDANCESTOR :
// case Axis.DESCENDANTSFROMROOT :
// case Axis.ALL :
// case Axis.DESCENDANTSORSELFFROMROOT :
// return BIT_ANY_DESCENDANT_FROM_ROOT;
// case Axis.ROOT :
// return BIT_ROOT;
// case Axis.FILTEREDLIST :
// return BIT_FILTER;
// default :
// return BIT_FILTER;
// }
// }
//
// static boolean functionProximateOrContainsProximate(Compiler compiler,
// int opPos)
// {
// int endFunc = opPos + compiler.getOp(opPos + 1) - 1;
// opPos = compiler.getFirstChildPos(opPos);
// int funcID = compiler.getOp(opPos);
// // System.out.println("funcID: "+funcID);
// // System.out.println("opPos: "+opPos);
// // System.out.println("endFunc: "+endFunc);
// switch(funcID)
// {
// case FunctionTable.FUNC_LAST:
// case FunctionTable.FUNC_POSITION:
// return true;
// default:
// opPos++;
// int i = 0;
// for (int p = opPos; p < endFunc; p = compiler.getNextOpPos(p), i++)
// {
// int innerExprOpPos = p+2;
// int argOp = compiler.getOp(innerExprOpPos);
// boolean prox = isProximateInnerExpr(compiler, innerExprOpPos);
// if(prox)
// return true;
// }
//
// }
// return false;
// }
//
// static boolean isProximateInnerExpr(Compiler compiler, int opPos)
// {
// int op = compiler.getOp(opPos);
// int innerExprOpPos = opPos+2;
// switch(op)
// {
// case OpCodes.OP_ARGUMENT:
// if(isProximateInnerExpr(compiler, innerExprOpPos))
// return true;
// break;
// case OpCodes.OP_VARIABLE:
// case OpCodes.OP_NUMBERLIT:
// case OpCodes.OP_LITERAL:
// case OpCodes.OP_LOCATIONPATH:
// break; // OK
// case OpCodes.OP_FUNCTION:
// boolean isProx = functionProximateOrContainsProximate(compiler, opPos);
// if(isProx)
// return true;
// break;
// case OpCodes.OP_GT:
// case OpCodes.OP_GTE:
// case OpCodes.OP_LT:
// case OpCodes.OP_LTE:
// case OpCodes.OP_EQUALS:
// int leftPos = compiler.getFirstChildPos(op);
// int rightPos = compiler.getNextOpPos(leftPos);
// isProx = isProximateInnerExpr(compiler, leftPos);
// if(isProx)
// return true;
// isProx = isProximateInnerExpr(compiler, rightPos);
// if(isProx)
// return true;
// break;
// default:
// return true; // be conservative...
// }
// return false;
// }
//
// /**
// * Tell if the predicates need to have proximity knowledge.
// */
// public static boolean mightBeProximate(Compiler compiler, int opPos, int stepType)
// throws javax.xml.transform.TransformerException
// {
//
// boolean mightBeProximate = false;
// int argLen;
//
// switch (stepType)
// {
// case OpCodes.OP_VARIABLE :
// case OpCodes.OP_EXTFUNCTION :
// case OpCodes.OP_FUNCTION :
// case OpCodes.OP_GROUP :
// argLen = compiler.getArgLength(opPos);
// break;
// default :
// argLen = compiler.getArgLengthOfStep(opPos);
// }
//
// int predPos = compiler.getFirstPredicateOpPos(opPos);
// int count = 0;
//
// while (OpCodes.OP_PREDICATE == compiler.getOp(predPos))
// {
// count++;
//
// int innerExprOpPos = predPos+2;
// int predOp = compiler.getOp(innerExprOpPos);
//
// switch(predOp)
// {
// case OpCodes.OP_VARIABLE:
// return true; // Would need more smarts to tell if this could be a number or not!
// case OpCodes.OP_LOCATIONPATH:
// // OK.
// break;
// case OpCodes.OP_NUMBER:
// case OpCodes.OP_NUMBERLIT:
// return true; // that's all she wrote!
// case OpCodes.OP_FUNCTION:
// boolean isProx
// = functionProximateOrContainsProximate(compiler, innerExprOpPos);
// if(isProx)
// return true;
// break;
// case OpCodes.OP_GT:
// case OpCodes.OP_GTE:
// case OpCodes.OP_LT:
// case OpCodes.OP_LTE:
// case OpCodes.OP_EQUALS:
// int leftPos = compiler.getFirstChildPos(innerExprOpPos);
// int rightPos = compiler.getNextOpPos(leftPos);
// isProx = isProximateInnerExpr(compiler, leftPos);
// if(isProx)
// return true;
// isProx = isProximateInnerExpr(compiler, rightPos);
// if(isProx)
// return true;
// break;
// default:
// return true; // be conservative...
// }
//
// predPos = compiler.getNextOpPos(predPos);
// }
//
// return mightBeProximate;
// }
//
// /**
// * Special purpose function to see if we can optimize the pattern for
// * a DescendantIterator.
// *
// * @param compiler non-null reference to compiler object that has processed
// * the XPath operations into an opcode map.
// * @param stepOpCodePos The opcode position for the step.
// * @param stepIndex The top-level step index withing the iterator.
// *
// * @return 32 bits as an integer that give information about the location
// * path as a whole.
// *
// * @throws javax.xml.transform.TransformerException
// */
// private static boolean isOptimizableForDescendantIterator(
// Compiler compiler, int stepOpCodePos, int stepIndex)
// throws javax.xml.transform.TransformerException
// {
//
// int stepType;
// int ops[] = compiler.getOpMap();
// int stepCount = 0;
// boolean foundDorDS = false;
// boolean foundSelf = false;
// boolean foundDS = false;
//
// int nodeTestType = OpCodes.NODETYPE_NODE;
//
// while (OpCodes.ENDOP != (stepType = ops[stepOpCodePos]))
// {
// // The DescendantIterator can only do one node test. If there's more
// // than one, use another iterator.
// if(nodeTestType != OpCodes.NODETYPE_NODE && nodeTestType != OpCodes.NODETYPE_ROOT)
// return false;
//
// stepCount++;
// if(stepCount > 3)
// return false;
//
// boolean mightBeProximate = mightBeProximate(compiler, stepOpCodePos, stepType);
// if(mightBeProximate)
// return false;
//
// switch (stepType)
// {
// case OpCodes.FROM_FOLLOWING :
// case OpCodes.FROM_FOLLOWING_SIBLINGS :
// case OpCodes.FROM_PRECEDING :
// case OpCodes.FROM_PRECEDING_SIBLINGS :
// case OpCodes.FROM_PARENT :
// case OpCodes.OP_VARIABLE :
// case OpCodes.OP_EXTFUNCTION :
// case OpCodes.OP_FUNCTION :
// case OpCodes.OP_GROUP :
// case OpCodes.FROM_NAMESPACE :
// case OpCodes.FROM_ANCESTORS :
// case OpCodes.FROM_ANCESTORS_OR_SELF :
// case OpCodes.FROM_ATTRIBUTES :
// case OpCodes.MATCH_ATTRIBUTE :
// case OpCodes.MATCH_ANY_ANCESTOR :
// case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
// return false;
// case OpCodes.FROM_ROOT :
// if(1 != stepCount)
// return false;
// break;
// case OpCodes.FROM_CHILDREN :
// if(!foundDS && !(foundDorDS && foundSelf))
// return false;
// break;
// case OpCodes.FROM_DESCENDANTS_OR_SELF :
// foundDS = true;
// case OpCodes.FROM_DESCENDANTS :
// if(3 == stepCount)
// return false;
// foundDorDS = true;
// break;
// case OpCodes.FROM_SELF :
// if(1 != stepCount)
// return false;
// foundSelf = true;
// break;
// default :
// throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
// // + stepType);
// }
//
// nodeTestType = compiler.getStepTestType(stepOpCodePos);
//
// int nextStepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
//
// if (nextStepOpCodePos < 0)
// break;
//
// if(OpCodes.ENDOP != ops[nextStepOpCodePos])
// {
// if(compiler.countPredicates(stepOpCodePos) > 0)
// {
// return false;
// }
// }
//
// stepOpCodePos = nextStepOpCodePos;
// }
//
// return true;
// }
//
// /**
// * Analyze the location path and return 32 bits that give information about
// * the location path as a whole. See the BIT_XXX constants for meaning about
// * each of the bits.
// *
// * @param compiler non-null reference to compiler object that has processed
// * the XPath operations into an opcode map.
// * @param stepOpCodePos The opcode position for the step.
// * @param stepIndex The top-level step index withing the iterator.
// *
// * @return 32 bits as an integer that give information about the location
// * path as a whole.
// *
// * @throws javax.xml.transform.TransformerException
// */
// private static int analyze(
// Compiler compiler, int stepOpCodePos, int stepIndex)
// throws javax.xml.transform.TransformerException
// {
//
// int stepType;
// int ops[] = compiler.getOpMap();
// int stepCount = 0;
// int analysisResult = 0x00000000; // 32 bits of analysis
//
// while (OpCodes.ENDOP != (stepType = ops[stepOpCodePos]))
// {
// stepCount++;
//
// // String namespace = compiler.getStepNS(stepOpCodePos);
// // boolean isNSWild = (null != namespace)
// // ? namespace.equals(NodeTest.WILD) : false;
// // String localname = compiler.getStepLocalName(stepOpCodePos);
// // boolean isWild = (null != localname) ? localname.equals(NodeTest.WILD) : false;
// boolean predAnalysis = analyzePredicate(compiler, stepOpCodePos,
// stepType);
//
// if (predAnalysis)
// analysisResult |= BIT_PREDICATE;
//
// switch (stepType)
// {
// case OpCodes.OP_VARIABLE :
// case OpCodes.OP_EXTFUNCTION :
// case OpCodes.OP_FUNCTION :
// case OpCodes.OP_GROUP :
// analysisResult |= BIT_FILTER;
// break;
// case OpCodes.FROM_ROOT :
// analysisResult |= BIT_ROOT;
// break;
// case OpCodes.FROM_ANCESTORS :
// analysisResult |= BIT_ANCESTOR;
// break;
// case OpCodes.FROM_ANCESTORS_OR_SELF :
// analysisResult |= BIT_ANCESTOR_OR_SELF;
// break;
// case OpCodes.FROM_ATTRIBUTES :
// analysisResult |= BIT_ATTRIBUTE;
// break;
// case OpCodes.FROM_NAMESPACE :
// analysisResult |= BIT_NAMESPACE;
// break;
// case OpCodes.FROM_CHILDREN :
// analysisResult |= BIT_CHILD;
// break;
// case OpCodes.FROM_DESCENDANTS :
// analysisResult |= BIT_DESCENDANT;
// break;
// case OpCodes.FROM_DESCENDANTS_OR_SELF :
//
// // Use a special bit to to make sure we get the right analysis of "//foo".
// if (2 == stepCount && BIT_ROOT == analysisResult)
// {
// analysisResult |= BIT_ANY_DESCENDANT_FROM_ROOT;
// }
//
// analysisResult |= BIT_DESCENDANT_OR_SELF;
// break;
// case OpCodes.FROM_FOLLOWING :
// analysisResult |= BIT_FOLLOWING;
// break;
// case OpCodes.FROM_FOLLOWING_SIBLINGS :
// analysisResult |= BIT_FOLLOWING_SIBLING;
// break;
// case OpCodes.FROM_PRECEDING :
// analysisResult |= BIT_PRECEDING;
// break;
// case OpCodes.FROM_PRECEDING_SIBLINGS :
// analysisResult |= BIT_PRECEDING_SIBLING;
// break;
// case OpCodes.FROM_PARENT :
// analysisResult |= BIT_PARENT;
// break;
// case OpCodes.FROM_SELF :
// analysisResult |= BIT_SELF;
// break;
// case OpCodes.MATCH_ATTRIBUTE :
// analysisResult |= (BIT_MATCH_PATTERN | BIT_ATTRIBUTE);
// break;
// case OpCodes.MATCH_ANY_ANCESTOR :
// analysisResult |= (BIT_MATCH_PATTERN | BIT_ANCESTOR);
// break;
// case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
// analysisResult |= (BIT_MATCH_PATTERN | BIT_PARENT);
// break;
// default :
// throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
// //+ stepType);
// }
//
// if (OpCodes.NODETYPE_NODE == ops[stepOpCodePos + 3]) // child::node()
// {
// analysisResult |= BIT_NODETEST_ANY;
// }
//
// stepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
//
// if (stepOpCodePos < 0)
// break;
// }
//
// analysisResult |= (stepCount & BITS_COUNT);
//
// return analysisResult;
// }
//
// /**
// * Tell if the given axis goes downword. Bogus name, if you can think of
// * a better one, please do tell. This really has to do with inverting
// * attribute axis.
// * @param axis One of Axis.XXX.
// * @return true if the axis is not a child axis and does not go up from
// * the axis root.
// */
// public static boolean isDownwardAxisOfMany(int axis)
// {
// return ((Axis.DESCENDANTORSELF == axis) ||
// (Axis.DESCENDANT == axis)
// || (Axis.FOLLOWING == axis)
//// || (Axis.FOLLOWINGSIBLING == axis)
// || (Axis.PRECEDING == axis)
//// || (Axis.PRECEDINGSIBLING == axis)
// );
// }
//
// /**
// * Read a <a href="http://www.w3.org/TR/xpath#location-paths">LocationPath</a>
// * as a generalized match pattern. What this means is that the LocationPath
// * is read backwards, as a test on a given node, to see if it matches the
// * criteria of the selection, and ends up at the context node. Essentially,
// * this is a backwards query from a given node, to find the context node.
// * <p>So, the selection "foo/daz[2]" is, in non-abreviated expanded syntax,
// * "self::node()/following-sibling::foo/child::daz[position()=2]".
// * Taking this as a match pattern for a probable node, it works out to
// * "self::daz/parent::foo[child::daz[position()=2 and isPrevStepNode()]
// * precedingSibling::node()[isContextNodeOfLocationPath()]", adding magic
// * isPrevStepNode and isContextNodeOfLocationPath operations. Predicates in
// * the location path have to be executed by the following step,
// * because they have to know the context of their execution.
// *
// * @param mpi The MatchPatternIterator to which the steps will be attached.
// * @param compiler The compiler that holds the syntax tree/op map to
// * construct from.
// * @param stepOpCodePos The current op code position within the opmap.
// * @param stepIndex The top-level step index withing the iterator.
// *
// * @return A StepPattern object, which may contain relative StepPatterns.
// *
// * @throws javax.xml.transform.TransformerException
// */
// static StepPattern loadSteps(
// MatchPatternIterator mpi, Compiler compiler, int stepOpCodePos,
// int stepIndex)
// throws javax.xml.transform.TransformerException
// {
// if (DEBUG_PATTERN_CREATION)
// {
// System.out.println("================");
// System.out.println("loadSteps for: "+compiler.getPatternString());
// }
// int stepType;
// StepPattern step = null;
// StepPattern firstStep = null, prevStep = null;
// int ops[] = compiler.getOpMap();
// int analysis = analyze(compiler, stepOpCodePos, stepIndex);
//
// while (OpCodes.ENDOP != (stepType = ops[stepOpCodePos]))
// {
// step = createDefaultStepPattern(compiler, stepOpCodePos, mpi, analysis,
// firstStep, prevStep);
//
// if (null == firstStep)
// {
// firstStep = step;
// }
// else
// {
//
// //prevStep.setNextWalker(step);
// step.setRelativePathPattern(prevStep);
// }
//
// prevStep = step;
// stepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
//
// if (stepOpCodePos < 0)
// break;
// }
//
// int axis = Axis.SELF;
// int paxis = Axis.SELF;
// StepPattern tail = step;
// for (StepPattern pat = step; null != pat;
// pat = pat.getRelativePathPattern())
// {
// int nextAxis = pat.getAxis();
// //int nextPaxis = pat.getPredicateAxis();
// pat.setAxis(axis);
//
// // The predicate axis can't be moved!!! Test Axes103
// // pat.setPredicateAxis(paxis);
//
// // If we have an attribute or namespace axis that went up, then
// // it won't find the attribute in the inverse, since the select-to-match
// // axes are not invertable (an element is a parent of an attribute, but
// // and attribute is not a child of an element).
// // If we don't do the magic below, then "@*/ancestor-or-self::*" gets
// // inverted for match to "self::*/descendant-or-self::@*/parent::node()",
// // which obviously won't work.
// // So we will rewrite this as:
// // "self::*/descendant-or-self::*/attribute::*/parent::node()"
// // Child has to be rewritten a little differently:
// // select: "@*/parent::*"
// // inverted match: "self::*/child::@*/parent::node()"
// // rewrite: "self::*/attribute::*/parent::node()"
// // Axes that go down in the select, do not have to have special treatment
// // in the rewrite. The following inverted match will still not select
// // anything.
// // select: "@*/child::*"
// // inverted match: "self::*/parent::@*/parent::node()"
// // Lovely business, this.
// // -sb
// int whatToShow = pat.getWhatToShow();
// if(whatToShow == DTMFilter.SHOW_ATTRIBUTE ||
// whatToShow == DTMFilter.SHOW_NAMESPACE)
// {
// int newAxis = (whatToShow == DTMFilter.SHOW_ATTRIBUTE) ?
// Axis.ATTRIBUTE : Axis.NAMESPACE;
// if(isDownwardAxisOfMany(axis))
// {
// StepPattern attrPat = new StepPattern(whatToShow,
// pat.getNamespace(),
// pat.getLocalName(),
// //newAxis, pat.getPredicateAxis);
// newAxis, 0); // don't care about the predicate axis
// XNumber score = pat.getStaticScore();
// pat.setNamespace(null);
// pat.setLocalName(NodeTest.WILD);
// attrPat.setPredicates(pat.getPredicates());
// pat.setPredicates(null);
// pat.setWhatToShow(DTMFilter.SHOW_ELEMENT);
// StepPattern rel = pat.getRelativePathPattern();
// pat.setRelativePathPattern(attrPat);
// attrPat.setRelativePathPattern(rel);
// attrPat.setStaticScore(score);
//
// // This is needed to inverse a following pattern, because of the
// // wacky Xalan rules for following from an attribute. See axes108.
// // By these rules, following from an attribute is not strictly
// // inverseable.
// if(Axis.PRECEDING == pat.getAxis())
// pat.setAxis(Axis.PRECEDINGANDANCESTOR);
//
// else if(Axis.DESCENDANT == pat.getAxis())
// pat.setAxis(Axis.DESCENDANTORSELF);
//
// pat = attrPat;
// }
// else if(Axis.CHILD == pat.getAxis())
// {
// // In this case just change the axis.
// // pat.setWhatToShow(whatToShow);
// pat.setAxis(Axis.ATTRIBUTE);
// }
// }
// axis = nextAxis;
// //paxis = nextPaxis;
// tail = pat;
// }
//
// if(axis < Axis.ALL)
// {
// StepPattern selfPattern = new ContextMatchStepPattern(axis, paxis);
// // We need to keep the new nodetest from affecting the score...
// XNumber score = tail.getStaticScore();
// tail.setRelativePathPattern(selfPattern);
// tail.setStaticScore(score);
// selfPattern.setStaticScore(score);
// }
//
// if (DEBUG_PATTERN_CREATION)
// {
// System.out.println("Done loading steps: "+step.toString());
//
// System.out.println("");
// }
// return step; // start from last pattern?? //firstStep;
// }
//
// /**
// * Create a StepPattern that is contained within a LocationPath.
// *
// *
// * @param compiler The compiler that holds the syntax tree/op map to
// * construct from.
// * @param stepOpCodePos The current op code position within the opmap.
// * @param mpi The MatchPatternIterator to which the steps will be attached.
// * @param analysis 32 bits of analysis, from which the type of AxesWalker
// * may be influenced.
// * @param tail The step that is the first step analyzed, but the last
// * step in the relative match linked list, i.e. the tail.
// * May be null.
// * @param head The step that is the current head of the relative
// * match step linked list.
// * May be null.
// *
// * @return the head of the list.
// *
// * @throws javax.xml.transform.TransformerException
// */
// private static StepPattern createDefaultStepPattern(
// Compiler compiler, int opPos, MatchPatternIterator mpi,
// int analysis, StepPattern tail, StepPattern head)
// throws javax.xml.transform.TransformerException
// {
//
// int stepType = compiler.getOp(opPos);
// boolean simpleInit = false;
// int totalNumberWalkers = (analysis & BITS_COUNT);
// boolean prevIsOneStepDown = true;
// int firstStepPos = compiler.getFirstChildPos(opPos);
//
// int whatToShow = compiler.getWhatToShow(opPos);
// StepPattern ai = null;
// int axis, predicateAxis;
//
// switch (stepType)
// {
// case OpCodes.OP_VARIABLE :
// case OpCodes.OP_EXTFUNCTION :
// case OpCodes.OP_FUNCTION :
// case OpCodes.OP_GROUP :
// prevIsOneStepDown = false;
//
// Expression expr;
//
// switch (stepType)
// {
// case OpCodes.OP_VARIABLE :
// case OpCodes.OP_EXTFUNCTION :
// case OpCodes.OP_FUNCTION :
// case OpCodes.OP_GROUP :
// expr = compiler.compile(opPos);
// break;
// default :
// expr = compiler.compile(opPos + 2);
// }
//
// axis = Axis.FILTEREDLIST;
// predicateAxis = Axis.FILTEREDLIST;
// ai = new FunctionPattern(expr, axis, predicateAxis);
// simpleInit = true;
// break;
// case OpCodes.FROM_ROOT :
// whatToShow = DTMFilter.SHOW_DOCUMENT
// | DTMFilter.SHOW_DOCUMENT_FRAGMENT;
//
// axis = Axis.ROOT;
// predicateAxis = Axis.ROOT;
// ai = new StepPattern(DTMFilter.SHOW_DOCUMENT |
// DTMFilter.SHOW_DOCUMENT_FRAGMENT,
// axis, predicateAxis);
// break;
// case OpCodes.FROM_ATTRIBUTES :
// whatToShow = DTMFilter.SHOW_ATTRIBUTE;
// axis = Axis.PARENT;
// predicateAxis = Axis.ATTRIBUTE;
// // ai = new StepPattern(whatToShow, Axis.SELF, Axis.SELF);
// break;
// case OpCodes.FROM_NAMESPACE :
// whatToShow = DTMFilter.SHOW_NAMESPACE;
// axis = Axis.PARENT;
// predicateAxis = Axis.NAMESPACE;
// // ai = new StepPattern(whatToShow, axis, predicateAxis);
// break;
// case OpCodes.FROM_ANCESTORS :
// axis = Axis.DESCENDANT;
// predicateAxis = Axis.ANCESTOR;
// break;
// case OpCodes.FROM_CHILDREN :
// axis = Axis.PARENT;
// predicateAxis = Axis.CHILD;
// break;
// case OpCodes.FROM_ANCESTORS_OR_SELF :
// axis = Axis.DESCENDANTORSELF;
// predicateAxis = Axis.ANCESTORORSELF;
// break;
// case OpCodes.FROM_SELF :
// axis = Axis.SELF;
// predicateAxis = Axis.SELF;
// break;
// case OpCodes.FROM_PARENT :
// axis = Axis.CHILD;
// predicateAxis = Axis.PARENT;
// break;
// case OpCodes.FROM_PRECEDING_SIBLINGS :
// axis = Axis.FOLLOWINGSIBLING;
// predicateAxis = Axis.PRECEDINGSIBLING;
// break;
// case OpCodes.FROM_PRECEDING :
// axis = Axis.FOLLOWING;
// predicateAxis = Axis.PRECEDING;
// break;
// case OpCodes.FROM_FOLLOWING_SIBLINGS :
// axis = Axis.PRECEDINGSIBLING;
// predicateAxis = Axis.FOLLOWINGSIBLING;
// break;
// case OpCodes.FROM_FOLLOWING :
// axis = Axis.PRECEDING;
// predicateAxis = Axis.FOLLOWING;
// break;
// case OpCodes.FROM_DESCENDANTS_OR_SELF :
// axis = Axis.ANCESTORORSELF;
// predicateAxis = Axis.DESCENDANTORSELF;
// break;
// case OpCodes.FROM_DESCENDANTS :
// axis = Axis.ANCESTOR;
// predicateAxis = Axis.DESCENDANT;
// break;
// default :
// throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
// //+ stepType);
// }
// if(null == ai)
// {
// whatToShow = compiler.getWhatToShow(opPos); // %REVIEW%
// ai = new StepPattern(whatToShow, compiler.getStepNS(opPos),
// compiler.getStepLocalName(opPos),
// axis, predicateAxis);
// }
//
// if (false || DEBUG_PATTERN_CREATION)
// {
// System.out.print("new step: "+ ai);
// System.out.print(", axis: " + Axis.names[ai.getAxis()]);
// System.out.print(", predAxis: " + Axis.names[ai.getAxis()]);
// System.out.print(", what: ");
// System.out.print(" ");
// ai.debugWhatToShow(ai.getWhatToShow());
// }
//
// int argLen = compiler.getFirstPredicateOpPos(opPos);
//
// ai.setPredicates(compiler.getCompiledPredicates(argLen));
//
// return ai;
// }
//
// /**
// * Analyze a step and give information about it's predicates. Right now this
// * just returns true or false if the step has a predicate.
// *
// * @param compiler non-null reference to compiler object that has processed
// * the XPath operations into an opcode map.
// * @param opPos The opcode position for the step.
// * @param stepType The type of step, one of OP_GROUP, etc.
// *
// * @return true if step has a predicate.
// *
// * @throws javax.xml.transform.TransformerException
// */
// static boolean analyzePredicate(Compiler compiler, int opPos, int stepType)
// throws javax.xml.transform.TransformerException
// {
//
// int argLen;
//
// switch (stepType)
// {
// case OpCodes.OP_VARIABLE :
// case OpCodes.OP_EXTFUNCTION :
// case OpCodes.OP_FUNCTION :
// case OpCodes.OP_GROUP :
// argLen = compiler.getArgLength(opPos);
// break;
// default :
// argLen = compiler.getArgLengthOfStep(opPos);
// }
//
// int pos = compiler.getFirstPredicateOpPos(opPos);
// int nPredicates = compiler.countPredicates(pos);
//
// return (nPredicates > 0) ? true : false;
// }
//
// /**
// * Create the proper Walker from the axes type.
// *
// * @param compiler non-null reference to compiler object that has processed
// * the XPath operations into an opcode map.
// * @param opPos The opcode position for the step.
// * @param lpi The owning location path iterator.
// * @param analysis 32 bits of analysis, from which the type of AxesWalker
// * may be influenced.
// *
// * @return non-null reference to AxesWalker derivative.
// * @throws RuntimeException if the input is bad.
// */
// private static AxesWalker createDefaultWalker(Compiler compiler, int opPos,
// WalkingIterator lpi, int analysis)
// {
//
// AxesWalker ai = null;
// int stepType = compiler.getOp(opPos);
//
// /*
// System.out.println("0: "+compiler.getOp(opPos));
// System.out.println("1: "+compiler.getOp(opPos+1));
// System.out.println("2: "+compiler.getOp(opPos+2));
// System.out.println("3: "+compiler.getOp(opPos+3));
// System.out.println("4: "+compiler.getOp(opPos+4));
// System.out.println("5: "+compiler.getOp(opPos+5));
// */
// boolean simpleInit = false;
// int totalNumberWalkers = (analysis & BITS_COUNT);
// boolean prevIsOneStepDown = true;
//
// switch (stepType)
// {
// case OpCodes.OP_VARIABLE :
// case OpCodes.OP_EXTFUNCTION :
// case OpCodes.OP_FUNCTION :
// case OpCodes.OP_GROUP :
// prevIsOneStepDown = false;
//
// if (DEBUG_WALKER_CREATION)
// System.out.println("new walker: FilterExprWalker: " + analysis
// + ", " + compiler.toString());
//
// ai = new FilterExprWalker(lpi);
// simpleInit = true;
// break;
// case OpCodes.FROM_ROOT :
// ai = new AxesWalker(lpi, Axis.ROOT);
// break;
// case OpCodes.FROM_ANCESTORS :
// prevIsOneStepDown = false;
// ai = new ReverseAxesWalker(lpi, Axis.ANCESTOR);
// break;
// case OpCodes.FROM_ANCESTORS_OR_SELF :
// prevIsOneStepDown = false;
// ai = new ReverseAxesWalker(lpi, Axis.ANCESTORORSELF);
// break;
// case OpCodes.FROM_ATTRIBUTES :
// ai = new AxesWalker(lpi, Axis.ATTRIBUTE);
// break;
// case OpCodes.FROM_NAMESPACE :
// ai = new AxesWalker(lpi, Axis.NAMESPACE);
// break;
// case OpCodes.FROM_CHILDREN :
// ai = new AxesWalker(lpi, Axis.CHILD);
// break;
// case OpCodes.FROM_DESCENDANTS :
// prevIsOneStepDown = false;
// ai = new AxesWalker(lpi, Axis.DESCENDANT);
// break;
// case OpCodes.FROM_DESCENDANTS_OR_SELF :
// prevIsOneStepDown = false;
// ai = new AxesWalker(lpi, Axis.DESCENDANTORSELF);
// break;
// case OpCodes.FROM_FOLLOWING :
// prevIsOneStepDown = false;
// ai = new AxesWalker(lpi, Axis.FOLLOWING);
// break;
// case OpCodes.FROM_FOLLOWING_SIBLINGS :
// prevIsOneStepDown = false;
// ai = new AxesWalker(lpi, Axis.FOLLOWINGSIBLING);
// break;
// case OpCodes.FROM_PRECEDING :
// prevIsOneStepDown = false;
// ai = new ReverseAxesWalker(lpi, Axis.PRECEDING);
// break;
// case OpCodes.FROM_PRECEDING_SIBLINGS :
// prevIsOneStepDown = false;
// ai = new ReverseAxesWalker(lpi, Axis.PRECEDINGSIBLING);
// break;
// case OpCodes.FROM_PARENT :
// prevIsOneStepDown = false;
// ai = new ReverseAxesWalker(lpi, Axis.PARENT);
// break;
// case OpCodes.FROM_SELF :
// ai = new AxesWalker(lpi, Axis.SELF);
// break;
// default :
// throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
// //+ stepType);
// }
//
// if (simpleInit)
// {
// ai.initNodeTest(DTMFilter.SHOW_ALL);
// }
// else
// {
// int whatToShow = compiler.getWhatToShow(opPos);
//
// /*
// System.out.print("construct: ");
// NodeTest.debugWhatToShow(whatToShow);
// System.out.println("or stuff: "+(whatToShow & (DTMFilter.SHOW_ATTRIBUTE
// | DTMFilter.SHOW_ELEMENT
// | DTMFilter.SHOW_PROCESSING_INSTRUCTION)));
// */
// if ((0 == (whatToShow
// & (DTMFilter.SHOW_ATTRIBUTE | DTMFilter.SHOW_NAMESPACE | DTMFilter.SHOW_ELEMENT
// | DTMFilter.SHOW_PROCESSING_INSTRUCTION))) || (whatToShow == DTMFilter.SHOW_ALL))
// ai.initNodeTest(whatToShow);
// else
// {
// ai.initNodeTest(whatToShow, compiler.getStepNS(opPos),
// compiler.getStepLocalName(opPos));
// }
// }
//
// return ai;
// }
//
// public static String getAnalysisString(int analysis)
// {
// StringBuffer buf = new StringBuffer();
// buf.append("count: "+getStepCount(analysis)+" ");
// if((analysis & BIT_NODETEST_ANY) != 0)
// {
// buf.append("NTANY|");
// }
// if((analysis & BIT_PREDICATE) != 0)
// {
// buf.append("PRED|");
// }
// if((analysis & BIT_ANCESTOR) != 0)
// {
// buf.append("ANC|");
// }
// if((analysis & BIT_ANCESTOR_OR_SELF) != 0)
// {
// buf.append("ANCOS|");
// }
// if((analysis & BIT_ATTRIBUTE) != 0)
// {
// buf.append("ATTR|");
// }
// if((analysis & BIT_CHILD) != 0)
// {
// buf.append("CH|");
// }
// if((analysis & BIT_DESCENDANT) != 0)
// {
// buf.append("DESC|");
// }
// if((analysis & BIT_DESCENDANT_OR_SELF) != 0)
// {
// buf.append("DESCOS|");
// }
// if((analysis & BIT_FOLLOWING) != 0)
// {
// buf.append("FOL|");
// }
// if((analysis & BIT_FOLLOWING_SIBLING) != 0)
// {
// buf.append("FOLS|");
// }
// if((analysis & BIT_NAMESPACE) != 0)
// {
// buf.append("NS|");
// }
// if((analysis & BIT_PARENT) != 0)
// {
// buf.append("P|");
// }
// if((analysis & BIT_PRECEDING) != 0)
// {
// buf.append("PREC|");
// }
// if((analysis & BIT_PRECEDING_SIBLING) != 0)
// {
// buf.append("PRECS|");
// }
// if((analysis & BIT_SELF) != 0)
// {
// buf.append(".|");
// }
// if((analysis & BIT_FILTER) != 0)
// {
// buf.append("FLT|");
// }
// if((analysis & BIT_ROOT) != 0)
// {
// buf.append("R|");
// }
// return buf.toString();
// }
//
// /** Set to true for diagnostics about walker creation */
// static final boolean DEBUG_PATTERN_CREATION = false;
//
// /** Set to true for diagnostics about walker creation */
// static final boolean DEBUG_WALKER_CREATION = false;
//
// /** Set to true for diagnostics about iterator creation */
// static final boolean DEBUG_ITERATOR_CREATION = false;
//
// public static boolean hasPredicate(int analysis)
// {
// return (0 != (analysis & BIT_PREDICATE));
// }
//
// public static boolean isWild(int analysis)
// {
// return (0 != (analysis & BIT_NODETEST_ANY));
// }
//
// public static boolean walksAncestors(int analysis)
// {
// return isSet(analysis, BIT_ANCESTOR | BIT_ANCESTOR_OR_SELF);
// }
//
// public static boolean walksAttributes(int analysis)
// {
// return (0 != (analysis & BIT_ATTRIBUTE));
// }
//
// public static boolean walksNamespaces(int analysis)
// {
// return (0 != (analysis & BIT_NAMESPACE));
// }
//
// public static boolean walksChildren(int analysis)
// {
// return (0 != (analysis & BIT_CHILD));
// }
//
// public static boolean walksDescendants(int analysis)
// {
// return isSet(analysis, BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF);
// }
//
// public static boolean walksSubtree(int analysis)
// {
// return isSet(analysis, BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF | BIT_CHILD);
// }
//
// public static boolean walksSubtreeOnlyMaybeAbsolute(int analysis)
// {
// return walksSubtree(analysis)
// && !walksExtraNodes(analysis)
// && !walksUp(analysis)
// && !walksSideways(analysis)
// ;
// }
//
// public static boolean walksSubtreeOnly(int analysis)
// {
// return walksSubtreeOnlyMaybeAbsolute(analysis)
// && !isAbsolute(analysis)
// ;
// }
//
// public static boolean walksFilteredList(int analysis)
// {
// return isSet(analysis, BIT_FILTER);
// }
//
// public static boolean walksSubtreeOnlyFromRootOrContext(int analysis)
// {
// return walksSubtree(analysis)
// && !walksExtraNodes(analysis)
// && !walksUp(analysis)
// && !walksSideways(analysis)
// && !isSet(analysis, BIT_FILTER)
// ;
// }
//
// public static boolean walksInDocOrder(int analysis)
// {
// return (walksSubtreeOnlyMaybeAbsolute(analysis)
// || walksExtraNodesOnly(analysis)
// || walksFollowingOnlyMaybeAbsolute(analysis))
// && !isSet(analysis, BIT_FILTER)
// ;
// }
//
// public static boolean walksFollowingOnlyMaybeAbsolute(int analysis)
// {
// return isSet(analysis, BIT_SELF | BIT_FOLLOWING_SIBLING | BIT_FOLLOWING)
// && !walksSubtree(analysis)
// && !walksUp(analysis)
// && !walksSideways(analysis)
// ;
// }
//
// public static boolean walksUp(int analysis)
// {
// return isSet(analysis, BIT_PARENT | BIT_ANCESTOR | BIT_ANCESTOR_OR_SELF);
// }
//
// public static boolean walksSideways(int analysis)
// {
// return isSet(analysis, BIT_FOLLOWING | BIT_FOLLOWING_SIBLING |
// BIT_PRECEDING | BIT_PRECEDING_SIBLING);
// }
//
// public static boolean walksExtraNodes(int analysis)
// {
// return isSet(analysis, BIT_NAMESPACE | BIT_ATTRIBUTE);
// }
//
// public static boolean walksExtraNodesOnly(int analysis)
// {
// return walksExtraNodes(analysis)
// && !isSet(analysis, BIT_SELF)
// && !walksSubtree(analysis)
// && !walksUp(analysis)
// && !walksSideways(analysis)
// && !isAbsolute(analysis)
// ;
// }
//
// public static boolean isAbsolute(int analysis)
// {
// return isSet(analysis, BIT_ROOT | BIT_FILTER);
// }
//
// public static boolean walksChildrenOnly(int analysis)
// {
// return walksChildren(analysis)
// && !isSet(analysis, BIT_SELF)
// && !walksExtraNodes(analysis)
// && !walksDescendants(analysis)
// && !walksUp(analysis)
// && !walksSideways(analysis)
// && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT))
// ;
// }
//
// public static boolean walksChildrenAndExtraAndSelfOnly(int analysis)
// {
// return walksChildren(analysis)
// && !walksDescendants(analysis)
// && !walksUp(analysis)
// && !walksSideways(analysis)
// && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT))
// ;
// }
//
// public static boolean walksDescendantsAndExtraAndSelfOnly(int analysis)
// {
// return !walksChildren(analysis)
// && walksDescendants(analysis)
// && !walksUp(analysis)
// && !walksSideways(analysis)
// && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT))
// ;
// }
//
// public static boolean walksSelfOnly(int analysis)
// {
// return isSet(analysis, BIT_SELF)
// && !walksSubtree(analysis)
// && !walksUp(analysis)
// && !walksSideways(analysis)
// && !isAbsolute(analysis)
// ;
// }
//
//
// public static boolean walksUpOnly(int analysis)
// {
// return !walksSubtree(analysis)
// && walksUp(analysis)
// && !walksSideways(analysis)
// && !isAbsolute(analysis)
// ;
// }
//
// public static boolean walksDownOnly(int analysis)
// {
// return walksSubtree(analysis)
// && !walksUp(analysis)
// && !walksSideways(analysis)
// && !isAbsolute(analysis)
// ;
// }
//
// public static boolean walksDownExtraOnly(int analysis)
// {
// return walksSubtree(analysis) && walksExtraNodes(analysis)
// && !walksUp(analysis)
// && !walksSideways(analysis)
// && !isAbsolute(analysis)
// ;
// }
//
// public static boolean canSkipSubtrees(int analysis)
// {
// return isSet(analysis, BIT_CHILD) | walksSideways(analysis);
// }
//
// public static boolean canCrissCross(int analysis)
// {
// // This could be done faster. Coded for clarity.
// if(walksSelfOnly(analysis))
// return false;
// else if(walksDownOnly(analysis) && !canSkipSubtrees(analysis))
// return false;
// else if(walksChildrenAndExtraAndSelfOnly(analysis))
// return false;
// else if(walksDescendantsAndExtraAndSelfOnly(analysis))
// return false;
// else if(walksUpOnly(analysis))
// return false;
// else if(walksExtraNodesOnly(analysis))
// return false;
// else if(walksSubtree(analysis)
// && (walksSideways(analysis)
// || walksUp(analysis)
// || canSkipSubtrees(analysis)))
// return true;
// else
// return false;
// }
//
// /**
// * Tell if the pattern can be 'walked' with the iteration steps in natural
// * document order, without duplicates.
// *
// * @param analysis The general analysis of the pattern.
// *
// * @return true if the walk can be done in natural order.
// *
// * @throws javax.xml.transform.TransformerException
// */
// static public boolean isNaturalDocOrder(int analysis)
// {
// if(canCrissCross(analysis) || isSet(analysis, BIT_NAMESPACE) ||
// walksFilteredList(analysis))
// return false;
//
// if(walksInDocOrder(analysis))
// return true;
//
// return false;
// }
//
// /**
// * Tell if the pattern can be 'walked' with the iteration steps in natural
// * document order, without duplicates.
// *
// * @param compiler non-null reference to compiler object that has processed
// * the XPath operations into an opcode map.
// * @param stepOpCodePos The opcode position for the step.
// * @param stepIndex The top-level step index withing the iterator.
// * @param analysis The general analysis of the pattern.
// *
// * @return true if the walk can be done in natural order.
// *
// * @throws javax.xml.transform.TransformerException
// */
// private static boolean isNaturalDocOrder(
// Compiler compiler, int stepOpCodePos, int stepIndex, int analysis)
// throws javax.xml.transform.TransformerException
// {
// if(canCrissCross(analysis))
// return false;
//
// // Namespaces can present some problems, so just punt if we're looking for
// // these.
// if(isSet(analysis, BIT_NAMESPACE))
// return false;
//
// // The following, preceding, following-sibling, and preceding sibling can
// // be found in doc order if we get to this point, but if they occur
// // together, they produce
// // duplicates, so it's better for us to eliminate this case so we don't
// // have to check for duplicates during runtime if we're using a
// // WalkingIterator.
// if(isSet(analysis, BIT_FOLLOWING | BIT_FOLLOWING_SIBLING) &&
// isSet(analysis, BIT_PRECEDING | BIT_PRECEDING_SIBLING))
// return false;
//
// // OK, now we have to check for select="@*/axis::*" patterns, which
// // can also cause duplicates to happen. But select="axis*/@::*" patterns
// // are OK, as are select="@foo/axis::*" patterns.
// // Unfortunately, we can't do this just via the analysis bits.
//
// int stepType;
// int ops[] = compiler.getOpMap();
// int stepCount = 0;
// boolean foundWildAttribute = false;
//
// // Steps that can traverse anything other than down a
// // subtree or that can produce duplicates when used in
// // combonation are counted with this variable.
// int potentialDuplicateMakingStepCount = 0;
//
// while (OpCodes.ENDOP != (stepType = ops[stepOpCodePos]))
// {
// stepCount++;
//
// switch (stepType)
// {
// case OpCodes.FROM_ATTRIBUTES :
// case OpCodes.MATCH_ATTRIBUTE :
// if(foundWildAttribute) // Maybe not needed, but be safe.
// return false;
//
// // This doesn't seem to work as a test for wild card. Hmph.
// // int nodeTestType = compiler.getStepTestType(stepOpCodePos);
//
// String localName = compiler.getStepLocalName(stepOpCodePos);
// // System.err.println("localName: "+localName);
// if(localName.equals("*"))
// {
// foundWildAttribute = true;
// }
// break;
// case OpCodes.FROM_FOLLOWING :
// case OpCodes.FROM_FOLLOWING_SIBLINGS :
// case OpCodes.FROM_PRECEDING :
// case OpCodes.FROM_PRECEDING_SIBLINGS :
// case OpCodes.FROM_PARENT :
// case OpCodes.OP_VARIABLE :
// case OpCodes.OP_EXTFUNCTION :
// case OpCodes.OP_FUNCTION :
// case OpCodes.OP_GROUP :
// case OpCodes.FROM_NAMESPACE :
// case OpCodes.FROM_ANCESTORS :
// case OpCodes.FROM_ANCESTORS_OR_SELF :
// case OpCodes.MATCH_ANY_ANCESTOR :
// case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
// case OpCodes.FROM_DESCENDANTS_OR_SELF :
// case OpCodes.FROM_DESCENDANTS :
// if(potentialDuplicateMakingStepCount > 0)
// return false;
// potentialDuplicateMakingStepCount++;
// case OpCodes.FROM_ROOT :
// case OpCodes.FROM_CHILDREN :
// case OpCodes.FROM_SELF :
// if(foundWildAttribute)
// return false;
// break;
// default :
// throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
// // + stepType);
// }
//
// int nextStepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
//
// if (nextStepOpCodePos < 0)
// break;
//
// stepOpCodePos = nextStepOpCodePos;
// }
//
// return true;
// }
//
// public static boolean isOneStep(int analysis)
// {
// return (analysis & BITS_COUNT) == 0x00000001;
// }
//
// public static int getStepCount(int analysis)
// {
// return (analysis & BITS_COUNT);
// }
//
// /**
// * First 8 bits are the number of top-level location steps. Hopefully
// * there will never be more that 255 location steps!!!
// */
// public static final int BITS_COUNT = 0x000000FF;
//
// /** 4 bits are reserved for future use. */
// public static final int BITS_RESERVED = 0x00000F00;
//
// /** Bit is on if the expression contains a top-level predicate. */
// public static final int BIT_PREDICATE = (0x00001000);
//
// /** Bit is on if any of the walkers contain an ancestor step. */
// public static final int BIT_ANCESTOR = (0x00001000 << 1);
//
// /** Bit is on if any of the walkers contain an ancestor-or-self step. */
// public static final int BIT_ANCESTOR_OR_SELF = (0x00001000 << 2);
//
// /** Bit is on if any of the walkers contain an attribute step. */
// public static final int BIT_ATTRIBUTE = (0x00001000 << 3);
//
// /** Bit is on if any of the walkers contain a child step. */
// public static final int BIT_CHILD = (0x00001000 << 4);
//
// /** Bit is on if any of the walkers contain a descendant step. */
// public static final int BIT_DESCENDANT = (0x00001000 << 5);
//
// /** Bit is on if any of the walkers contain a descendant-or-self step. */
// public static final int BIT_DESCENDANT_OR_SELF = (0x00001000 << 6);
//
// /** Bit is on if any of the walkers contain a following step. */
// public static final int BIT_FOLLOWING = (0x00001000 << 7);
//
// /** Bit is on if any of the walkers contain a following-sibiling step. */
// public static final int BIT_FOLLOWING_SIBLING = (0x00001000 << 8);
//
// /** Bit is on if any of the walkers contain a namespace step. */
// public static final int BIT_NAMESPACE = (0x00001000 << 9);
//
// /** Bit is on if any of the walkers contain a parent step. */
// public static final int BIT_PARENT = (0x00001000 << 10);
//
// /** Bit is on if any of the walkers contain a preceding step. */
// public static final int BIT_PRECEDING = (0x00001000 << 11);
//
// /** Bit is on if any of the walkers contain a preceding-sibling step. */
// public static final int BIT_PRECEDING_SIBLING = (0x00001000 << 12);
//
// /** Bit is on if any of the walkers contain a self step. */
// public static final int BIT_SELF = (0x00001000 << 13);
//
// /**
// * Bit is on if any of the walkers contain a filter (i.e. id(), extension
// * function, etc.) step.
// */
// public static final int BIT_FILTER = (0x00001000 << 14);
//
// /** Bit is on if any of the walkers contain a root step. */
// public static final int BIT_ROOT = (0x00001000 << 15);
//
// /**
// * If any of these bits are on, the expression may likely traverse outside
// * the given subtree.
// */
// public static final int BITMASK_TRAVERSES_OUTSIDE_SUBTREE = (BIT_NAMESPACE // ??
// | BIT_PRECEDING_SIBLING
// | BIT_PRECEDING
// | BIT_FOLLOWING_SIBLING
// | BIT_FOLLOWING
// | BIT_PARENT // except parent of attrs.
// | BIT_ANCESTOR_OR_SELF
// | BIT_ANCESTOR
// | BIT_FILTER
// | BIT_ROOT);
//
// /**
// * Bit is on if any of the walkers can go backwards in document
// * order from the context node.
// */
// public static final int BIT_BACKWARDS_SELF = (0x00001000 << 16);
//
// /** Found "//foo" pattern */
// public static final int BIT_ANY_DESCENDANT_FROM_ROOT = (0x00001000 << 17);
//
// /**
// * Bit is on if any of the walkers contain an node() test. This is
// * really only useful if the count is 1.
// */
// public static final int BIT_NODETEST_ANY = (0x00001000 << 18);
//
// // can't go higher than 18!
//
// /** Bit is on if the expression is a match pattern. */
// public static final int BIT_MATCH_PATTERN = (0x00001000 << 19);
//}