blob: f15810f6125b843dada882553c7d7bd05121c4ba [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 org.apache.xpath.compiler.OpCodes;
import org.apache.xpath.compiler.Compiler;
import org.apache.xpath.patterns.NodeTest;
import org.w3c.dom.traversal.NodeFilter;
/**
* 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(
LocPathIterator 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(
LocPathIterator 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.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;
}
/**
* 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 LocPathIterator newLocPathIterator(
Compiler compiler, int opPos)
throws javax.xml.transform.TransformerException
{
int firstStepPos = compiler.getFirstChildPos(opPos);
int analysis = analyze(compiler, firstStepPos, 0);
// Is the iteration exactly one child step?
if ((BIT_CHILD | 0x00000001) == (analysis & (BIT_CHILD | BITS_COUNT)))
{
// BIT_NODETEST_ANY: 1000000000000000000000000000000
// BIT_PREDICATE: 1000000000000
// new iterator: ChildIterator: 1000000000000010000000000000001, node()
// Does the pattern specify *any* child with no predicate? (i.e. select="child::node()".
if ((BIT_NODETEST_ANY == (analysis & BIT_NODETEST_ANY)) &&
!(BIT_PREDICATE == (analysis & BIT_PREDICATE)))
{
if (DEBUG_ITERATOR_CREATION)
System.out.println("new iterator: ChildIterator: "
+ Integer.toBinaryString(analysis) + ", "
+ compiler.toString());
// Use simple child iteration without any test.
return new ChildIterator(compiler, opPos, analysis);
}
else
{
if (DEBUG_ITERATOR_CREATION)
System.out.println("new iterator: ChildTestIterator: "
+ Integer.toBinaryString(analysis) + ", "
+ compiler.toString());
// Else use simple node test iteration with predicate test.
return new ChildTestIterator(compiler, opPos, analysis);
}
}
// Is the iteration a one-step attribute pattern (i.e. select="@foo")?
else if ((BIT_ATTRIBUTE | 0x00000001)
== (analysis & (BIT_ATTRIBUTE | BITS_COUNT)))
{
if (DEBUG_ITERATOR_CREATION)
System.out.println("new iterator: AttributeIterator: "
+ Integer.toBinaryString(analysis) + ", "
+ compiler.toString());
// Then use a simple iteration of the attributes, with node test
// and predicate testing.
return new AttributeIterator(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 (0 == (BIT_PREDICATE & analysis) &&
(((BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF | 0x00000001)
== (analysis
& (BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF | BITS_COUNT))) ||
((BIT_DESCENDANT_OR_SELF | BIT_SELF | 0x00000002)
== (analysis
& (BIT_DESCENDANT_OR_SELF | BIT_SELF | BITS_COUNT)))
/* ".//center" -- 1000010000001010000000000000011 */
|| ((BIT_DESCENDANT_OR_SELF | BIT_SELF | BIT_CHILD | BIT_NODETEST_ANY | 0x00000003)
== (analysis
& (BIT_DESCENDANT_OR_SELF | BIT_SELF | BIT_CHILD | BIT_NODETEST_ANY | BITS_COUNT)))
/* "//center" -- 1001000000001010000000000000011 */
|| ((BIT_DESCENDANT_OR_SELF | BIT_ROOT | BIT_CHILD | BIT_NODETEST_ANY |
BIT_ANY_DESCENDANT_FROM_ROOT | 0x00000003)
== (analysis
& (BIT_DESCENDANT_OR_SELF | BIT_ROOT | BIT_CHILD |
BIT_NODETEST_ANY | BIT_ANY_DESCENDANT_FROM_ROOT | BITS_COUNT))))
)
{
if (DEBUG_ITERATOR_CREATION)
System.out.println("new iterator: DescendantIterator: "
+ Integer.toBinaryString(analysis) + ", "
+ compiler.toString());
return new DescendantIterator(compiler, opPos, analysis);
}
else
{
if (DEBUG_ITERATOR_CREATION)
System.out.println("new iterator: LocPathIterator: "
+ Integer.toBinaryString(analysis) + ", "
+ compiler.toString());
return new LocPathIterator(compiler, opPos, analysis, 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_DESCENDANT_OR_SELF;
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("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;
}
/**
* 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,
LocPathIterator lpi, int analysis)
{
AxesWalker ai;
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 :
if (0 == (analysis & ~(BIT_ROOT | BIT_CHILD | BIT_ATTRIBUTE |
BIT_NAMESPACE | BIT_PREDICATE | BITS_COUNT)))
{
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: RootWalkerMultiStep: " + analysis
+ ", " + compiler.toString());
ai = new RootWalkerMultiStep(lpi);
}
else
{
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: RootWalker: " + analysis
+ ", " + compiler.toString());
ai = new RootWalker(lpi);
}
break;
case OpCodes.FROM_ANCESTORS :
prevIsOneStepDown = false;
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: AncestorWalker: " + analysis
+ ", " + compiler.toString());
ai = new AncestorWalker(lpi);
break;
case OpCodes.FROM_ANCESTORS_OR_SELF :
prevIsOneStepDown = false;
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: AncestorOrSelfWalker: " + analysis
+ ", " + compiler.toString());
ai = new AncestorOrSelfWalker(lpi);
break;
case OpCodes.FROM_ATTRIBUTES :
if (1 == totalNumberWalkers)
{
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: AttributeWalkerOneStep: " + analysis
+ ", " + compiler.toString());
// TODO: We should be able to do this as long as this is
// the last step.
ai = new AttributeWalkerOneStep(lpi);
}
else
{
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: AttributeWalker: " + analysis
+ ", " + compiler.toString());
ai = new AttributeWalker(lpi);
}
break;
case OpCodes.FROM_NAMESPACE :
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: NamespaceWalker: " + analysis
+ ", " + compiler.toString());
ai = new NamespaceWalker(lpi);
break;
case OpCodes.FROM_CHILDREN :
if (1 == totalNumberWalkers)
{
// I don't think this will ever happen any more. -sb
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: ChildWalkerOneStep: " + analysis + ", "
+ compiler.toString());
ai = new ChildWalkerOneStep(lpi);
}
else
{
if (0 == (analysis & ~(BIT_ROOT | BIT_CHILD | BIT_ATTRIBUTE |
BIT_NAMESPACE | BIT_PREDICATE | BITS_COUNT)))
{
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: ChildWalkerMultiStep: " + analysis
+ ", " + compiler.toString());
ai = new ChildWalkerMultiStep(lpi);
}
else
{
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: ChildWalker: " + analysis
+ ", " + compiler.toString());
ai = new ChildWalker(lpi);
}
}
break;
case OpCodes.FROM_DESCENDANTS :
prevIsOneStepDown = false;
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: DescendantWalker: " + analysis
+ ", " + compiler.toString());
ai = new DescendantWalker(lpi);
break;
case OpCodes.FROM_DESCENDANTS_OR_SELF :
prevIsOneStepDown = false;
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: DescendantOrSelfWalker: " + analysis
+ ", " + compiler.toString());
ai = new DescendantOrSelfWalker(lpi);
break;
case OpCodes.FROM_FOLLOWING :
prevIsOneStepDown = false;
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: FollowingWalker: " + analysis
+ ", " + compiler.toString());
ai = new FollowingWalker(lpi);
break;
case OpCodes.FROM_FOLLOWING_SIBLINGS :
prevIsOneStepDown = false;
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: FollowingSiblingWalker: " + analysis
+ ", " + compiler.toString());
ai = new FollowingSiblingWalker(lpi);
break;
case OpCodes.FROM_PRECEDING :
prevIsOneStepDown = false;
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: PrecedingWalker: " + analysis
+ ", " + compiler.toString());
ai = new PrecedingWalker(lpi);
break;
case OpCodes.FROM_PRECEDING_SIBLINGS :
prevIsOneStepDown = false;
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: PrecedingSiblingWalker: " + analysis
+ ", " + compiler.toString());
ai = new PrecedingSiblingWalker(lpi);
break;
case OpCodes.FROM_PARENT :
prevIsOneStepDown = false;
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: ParentWalker: " + analysis
+ ", " + compiler.toString());
ai = new ParentWalker(lpi);
break;
case OpCodes.FROM_SELF :
if (1 == totalNumberWalkers)
{
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: SelfWalkerOneStep: " + analysis
+ ", " + compiler.toString());
ai = new SelfWalkerOneStep(lpi);
}
else
{
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: SelfWalker: " + analysis
+ ", " + compiler.toString());
ai = new SelfWalker(lpi);
}
break;
case OpCodes.MATCH_ATTRIBUTE :
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: AttributeWalker(MATCH_ATTRIBUTE): " + analysis
+ ", " + compiler.toString());
ai = new AttributeWalker(lpi);
break;
case OpCodes.MATCH_ANY_ANCESTOR :
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: ChildWalker(MATCH_ANY_ANCESTOR): " + analysis
+ ", " + compiler.toString());
ai = new ChildWalker(lpi);
break;
case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
if (DEBUG_WALKER_CREATION)
System.out.println("new walker: ChildWalker(MATCH_IMMEDIATE_ANCESTOR): " + analysis
+ ", " + compiler.toString());
ai = new ChildWalker(lpi);
break;
default :
throw new RuntimeException("Programmer's assertion: unknown opcode: "
+ stepType);
}
if (simpleInit)
{
ai.initNodeTest(NodeFilter.SHOW_ALL);
}
else
{
int whatToShow = compiler.getWhatToShow(opPos);
/*
System.out.print("construct: ");
NodeTest.debugWhatToShow(whatToShow);
System.out.println("or stuff: "+(whatToShow & (NodeFilter.SHOW_ATTRIBUTE
| NodeFilter.SHOW_ELEMENT
| NodeFilter.SHOW_PROCESSING_INSTRUCTION)));
*/
if ((0 == (whatToShow
& (NodeFilter.SHOW_ATTRIBUTE | NodeFilter.SHOW_ELEMENT
| NodeFilter.SHOW_PROCESSING_INSTRUCTION))) || (whatToShow == NodeFilter.SHOW_ALL))
ai.initNodeTest(whatToShow);
else
{
ai.initNodeTest(whatToShow, compiler.getStepNS(opPos),
compiler.getStepLocalName(opPos));
}
}
return ai;
}
/** 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;
/**
* 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);
}