sboag 00/12/14 18:30:40
Modified: java/src/org/apache/xpath/axes AttributeWalkerOneStep.java
AxesWalker.java DescendantWalker.java
WalkerFactory.java
Added: java/src/org/apache/xpath/axes DescendantIterator.java
Log:
Re-worked analysis in Walker factory so that it is more sane. It now
uses a bit scheme instead of enumerated values for the analysis.
Added DescendantIterator which optimizes "//foo" patterns as well
as "descendant-or-self::foo", "descendant::foo", and ".//foo" patterns.
ToDo: It would probably be nice to add handling of "//foo/@attr"
patterns also, since the attributes do not have the danger of overlapping
in document order, as child patterns do.
Revision Changes Path
1.4 +1 -1
xml-xalan/java/src/org/apache/xpath/axes/AttributeWalkerOneStep.java
Index: AttributeWalkerOneStep.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xpath/axes/AttributeWalkerOneStep.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- AttributeWalkerOneStep.java 2000/11/15 19:41:05 1.3
+++ AttributeWalkerOneStep.java 2000/12/15 02:30:39 1.4
@@ -81,7 +81,7 @@
/**
* The root node of the TreeWalker.
*
- * NEEDSDOC @param root
+ * @param root The context node of the node step.
*/
public void setRoot(Node root)
{
1.13 +1 -1 xml-xalan/java/src/org/apache/xpath/axes/AxesWalker.java
Index: AxesWalker.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/axes/AxesWalker.java,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- AxesWalker.java 2000/12/09 03:56:47 1.12
+++ AxesWalker.java 2000/12/15 02:30:39 1.13
@@ -238,7 +238,7 @@
* The type of this walker based on the pattern analysis.
* @see org.apache.xpath.axes.WalkerFactory
*/
- protected int m_analysis = WalkerFactory.NO_OPTIMIZE;
+ protected int m_analysis = 0x00000000;
/**
* NEEDSDOC Method getAnalysis
1.3 +1 -1
xml-xalan/java/src/org/apache/xpath/axes/DescendantWalker.java
Index: DescendantWalker.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xpath/axes/DescendantWalker.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- DescendantWalker.java 2000/10/30 18:58:48 1.2
+++ DescendantWalker.java 2000/12/15 02:30:39 1.3
@@ -105,7 +105,7 @@
Node n;
- if (m_root.equals(m_currentNode))
+ if (m_root.equals(m_currentNode)) // why not == ? -sb
{
n = null;
}
1.9 +271 -169
xml-xalan/java/src/org/apache/xpath/axes/WalkerFactory.java
Index: WalkerFactory.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xpath/axes/WalkerFactory.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- WalkerFactory.java 2000/12/13 21:54:43 1.8
+++ WalkerFactory.java 2000/12/15 02:30:39 1.9
@@ -63,8 +63,9 @@
import org.w3c.dom.traversal.NodeFilter;
/**
- * <meta name="usage" content="internal"/>
- * NEEDSDOC Class WalkerFactory <needs-comment/>
+ * 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
{
@@ -76,11 +77,12 @@
* @param xpath The xpath that is executing.
* @param context The current source tree context node.
*
- * NEEDSDOC @param lpi
- * NEEDSDOC @param compiler
- * NEEDSDOC @param stepOpCodePos
+ * @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.
*
- * NEEDSDOC ($objectName$) @return
+ * @return non-null AxesWalker derivative.
*
* @throws javax.xml.transform.TransformerException
*/
@@ -112,12 +114,13 @@
* @param xpath The xpath that is executing.
* @param context The current source tree context node.
*
- * NEEDSDOC @param lpi
- * NEEDSDOC @param compiler
- * NEEDSDOC @param stepOpCodePos
- * NEEDSDOC @param stepIndex
+ * @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.
*
- * NEEDSDOC ($objectName$) @return
+ * @return non-null AxesWalker derivative.
*
* @throws javax.xml.transform.TransformerException
*/
@@ -160,34 +163,83 @@
}
/**
- * NEEDSDOC Method newLocPathIterator
+ * 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.
*
- * NEEDSDOC @param compiler
- * NEEDSDOC @param opPos
+ * @return non-null reference to a LocPathIterator or derivative.
*
- * NEEDSDOC (newLocPathIterator) @return
- *
* @throws javax.xml.transform.TransformerException
*/
public static LocPathIterator newLocPathIterator(
- Compiler compiler, int opPos) throws
javax.xml.transform.TransformerException
+ Compiler compiler, int opPos)
+ throws javax.xml.transform.TransformerException
{
int firstStepPos = compiler.getFirstChildPos(opPos);
int analysis = analyze(compiler, firstStepPos, 0);
+
+
+ if (DEBUG_ITERATOR_CREATION)
+ System.out.println("analysis -- newLocPathIterator: "
+ + Integer.toBinaryString(analysis) + ", "
+ + compiler.toString());
+
+ // Can't have optimized iterators at this time that have predicates.
+ if (BIT_PREDICATE == (analysis & BIT_PREDICATE))
+ return new LocPathIterator(compiler, opPos, true);
- if (ONESTEP_CHILDREN_ANY == analysis)
+ if ((BIT_CHILD | 0x00000001) == (analysis & (BIT_CHILD | BITS_COUNT)))
{
- return new ChildIterator(compiler, opPos);
+ if (BIT_CHILD == (analysis & BIT_NODETEST_ANY))
+ {
+ if (DEBUG_ITERATOR_CREATION)
+ System.out.println("ChildIterator!");
+
+ return new ChildIterator(compiler, opPos);
+ }
+ else
+ {
+ if (DEBUG_ITERATOR_CREATION)
+ System.out.println("ChildTestIterator!");
+
+ return new ChildTestIterator(compiler, opPos);
+ }
}
- else if(ONESTEP_CHILDREN_NO_PREDICATE == analysis)
+ else if ((BIT_ATTRIBUTE | 0x00000001)
+ == (analysis & (BIT_ATTRIBUTE | BITS_COUNT)))
{
- return new ChildTestIterator(compiler, opPos);
+ if (DEBUG_ITERATOR_CREATION)
+ System.out.println("AttributeIterator!");
+
+ return new AttributeIterator(compiler, opPos);
}
- else if(ONESTEP_ATTR_NO_PREDICATES == 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.
+ else if (((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))) ||
+ ((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)))
+ )
{
- return new AttributeIterator(compiler, opPos);
+ if (DEBUG_ITERATOR_CREATION)
+ System.out.println("DescendantIterator!");
+
+ return new DescendantIterator(compiler, opPos);
}
else
{
@@ -195,45 +247,19 @@
}
}
- // There is no optimized walker that can handle
- // this pattern, so use the default.
-
- /** Pattern that we do not optimize for. */
- static final int NO_OPTIMIZE = 1;
-
- /** "." */
- static final int ONESTEP_SELF = 2;
-
- /** "*" */
- static final int ONESTEP_CHILDREN = 3;
-
- /** "node()" */
- static final int ONESTEP_CHILDREN_ANY = 7;
-
- /** "@foo[../baz]" */
- static final int ONESTEP_ATTR = 4;
-
- /** "@foo" */
- static final int ONESTEP_ATTR_NO_PREDICATES = 9;
-
- /** NEEDSDOC Field ONESTEP_DESCENDANTS */
- static final int ONESTEP_DESCENDANTS = 5;
-
- /** NEEDSDOC Field MULTISTEP_CHILDREN */
- static final int MULTISTEP_CHILDREN = 6;
-
- /** NEEDSDOC Field ONESTEP_CHILDREN */
- static final int ONESTEP_CHILDREN_NO_PREDICATE = 8;
-
/**
- * <meta name="usage" content="advanced"/>
+ * 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.
*
- * NEEDSDOC @param compiler
- * NEEDSDOC @param stepOpCodePos
- * NEEDSDOC @param stepIndex
+ * @return 32 bits as an integer that give information about the location
+ * path as a whole.
*
- * NEEDSDOC ($objectName$) @return
- *
* @throws javax.xml.transform.TransformerException
*/
private static int analyze(
@@ -244,7 +270,7 @@
int stepType;
int ops[] = compiler.getOpMap();
int stepCount = 0;
- int analysisResult = NO_OPTIMIZE;
+ int analysisResult = 0x00000000; // 32 bits of analysis
while (OpCodes.ENDOP != (stepType = ops[stepOpCodePos]))
{
@@ -255,128 +281,111 @@
// ? namespace.equals(NodeTest.WILD) : false;
// String localname = compiler.getStepLocalName(stepOpCodePos);
// boolean isWild = (null != localname) ?
localname.equals(NodeTest.WILD) : false;
- int predAnalysis = analyzePredicate(compiler, stepOpCodePos, stepType);
+ 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 :
- return NO_OPTIMIZE; // at least for now
+ analysisResult |= BIT_FILTER;
+ break;
case OpCodes.FROM_ROOT :
- return NO_OPTIMIZE; // at least for now
+ analysisResult |= BIT_ROOT;
+ break;
case OpCodes.FROM_ANCESTORS :
- return NO_OPTIMIZE; // at least for now
+ analysisResult |= BIT_ANCESTOR;
+ break;
case OpCodes.FROM_ANCESTORS_OR_SELF :
- return NO_OPTIMIZE; // at least for now
+ analysisResult |= BIT_ANCESTOR_OR_SELF;
+ break;
case OpCodes.FROM_ATTRIBUTES :
- if (1 == stepCount)
- {
- if(predAnalysis == HAS_NOPREDICATE)
- analysisResult = ONESTEP_ATTR_NO_PREDICATES;
- else
- analysisResult = ONESTEP_ATTR;
- }
- else
- {
- return NO_OPTIMIZE; // at least for now
- }
+ analysisResult |= BIT_ATTRIBUTE;
break;
case OpCodes.FROM_NAMESPACE :
- return NO_OPTIMIZE; // at least for now
+ analysisResult |= BIT_NAMESPACE;
+ break;
case OpCodes.FROM_CHILDREN :
- if (1 == stepCount)
- {
- if (OpCodes.NODETYPE_NODE == ops[stepOpCodePos+3]) //
child::node()
- {
- // System.out.println("ONESTEP_CHILDREN_ANY");
- if(predAnalysis == HAS_NOPREDICATE)
- analysisResult = ONESTEP_CHILDREN_ANY;
- else
- analysisResult = NO_OPTIMIZE;
- }
- else
- {
- if(predAnalysis == HAS_NOPREDICATE)
- analysisResult = ONESTEP_CHILDREN_NO_PREDICATE;
- else
- analysisResult = ONESTEP_CHILDREN;
- }
- }
- else
- {
- if ((analysisResult == ONESTEP_CHILDREN)
- || (analysisResult == MULTISTEP_CHILDREN))
- analysisResult = MULTISTEP_CHILDREN;
- else
- return NO_OPTIMIZE;
- }
+ analysisResult |= BIT_CHILD;
break;
case OpCodes.FROM_DESCENDANTS :
- return NO_OPTIMIZE; // TODO
+ analysisResult |= BIT_DESCENDANT;
+ break;
case OpCodes.FROM_DESCENDANTS_OR_SELF :
- return NO_OPTIMIZE; // TODO
+ // 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 :
- return NO_OPTIMIZE; // at least for now
+ analysisResult |= BIT_DESCENDANT_OR_SELF;
+ break;
case OpCodes.FROM_FOLLOWING_SIBLINGS :
- return NO_OPTIMIZE; // at least for now
+ analysisResult |= BIT_FOLLOWING_SIBLING;
+ break;
case OpCodes.FROM_PRECEDING :
- return NO_OPTIMIZE; // at least for now
+ analysisResult |= BIT_PRECEDING;
+ break;
case OpCodes.FROM_PRECEDING_SIBLINGS :
- return NO_OPTIMIZE; // at least for now
+ analysisResult |= BIT_PRECEDING_SIBLING;
+ break;
case OpCodes.FROM_PARENT :
- return NO_OPTIMIZE; // at least for now
+ analysisResult |= BIT_PARENT;
+ break;
case OpCodes.FROM_SELF :
- if (1 == stepCount)
- analysisResult = ONESTEP_SELF;
- else
- return NO_OPTIMIZE; // at least for now
+ analysisResult |= BIT_SELF;
break;
case OpCodes.MATCH_ATTRIBUTE :
- return NO_OPTIMIZE; // for now we shouldn't be dealing with match
patterns here.
+ analysisResult |= (BIT_MATCH_PATTERN | BIT_ATTRIBUTE);
+ break;
case OpCodes.MATCH_ANY_ANCESTOR :
- return NO_OPTIMIZE; // for now we shouldn't be dealing with match
patterns here.
+ analysisResult |= (BIT_MATCH_PATTERN | BIT_ANCESTOR);
+ break;
case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
- return NO_OPTIMIZE; // for now we shouldn't be dealing with match
patterns here.
+ 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;
}
- /** NEEDSDOC Field HAS_PREDICATE */
- static final int HAS_PREDICATE = 1;
-
- /** NEEDSDOC Field HAS_NOPREDICATE */
- static final int HAS_NOPREDICATE = 2;
-
- /** NEEDSDOC Field HAS_BOOLEANPREDICATE */
- static final int HAS_BOOLEANPREDICATE = 3;
-
- /** NEEDSDOC Field MAYHAVE_INDEXPREDICATE */
- static final int MAYHAVE_INDEXPREDICATE = 4;
-
/**
- * NEEDSDOC Method analyzePredicate
- *
+ * Analyze a step and give information about it's predicates. Right now
this
+ * just returns true or false if the step has a predicate.
*
- * NEEDSDOC @param compiler
- * NEEDSDOC @param opPos
- * NEEDSDOC @param stepType
+ * @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.
*
- * NEEDSDOC (analyzePredicate) @return
+ * @return true if step has a predicate.
*
* @throws javax.xml.transform.TransformerException
*/
- static int analyzePredicate(Compiler compiler, int opPos, int stepType)
+ static boolean analyzePredicate(Compiler compiler, int opPos, int stepType)
throws javax.xml.transform.TransformerException
{
@@ -397,18 +406,21 @@
int pos = compiler.getFirstPredicateOpPos(opPos);
int nPredicates = compiler.countPredicates(pos);
- return (nPredicates > 0) ? HAS_PREDICATE : HAS_NOPREDICATE;
+ return (nPredicates > 0) ? true : false;
}
/**
* Create the proper Walker from the axes type.
*
- * NEEDSDOC @param compiler
- * NEEDSDOC @param opPos
- * NEEDSDOC @param lpi
- * NEEDSDOC @param analysis
+ * @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.
*
- * NEEDSDOC ($objectName$) @return
+ * @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)
@@ -416,7 +428,6 @@
AxesWalker ai;
int stepType = compiler.getOp(opPos);
- boolean debug = false;
/*
System.out.println("0: "+compiler.getOp(opPos));
@@ -427,6 +438,7 @@
System.out.println("5: "+compiler.getOp(opPos+5));
*/
boolean simpleInit = false;
+ int totalNumberWalkers = (analysis & BITS_COUNT);
switch (stepType)
{
@@ -447,40 +459,42 @@
ai = new AncestorOrSelfWalker(lpi);
break;
case OpCodes.FROM_ATTRIBUTES :
- switch (analysis)
+ if (1 == totalNumberWalkers)
{
- case ONESTEP_ATTR_NO_PREDICATES:
- case ONESTEP_ATTR :
+
+ // TODO: We should be able to do this as long as this is
+ // the last step.
ai = new AttributeWalkerOneStep(lpi);
- break;
- default :
- ai = new AttributeWalker(lpi);
}
+ else
+ ai = new AttributeWalker(lpi);
break;
case OpCodes.FROM_NAMESPACE :
ai = new NamespaceWalker(lpi);
break;
case OpCodes.FROM_CHILDREN :
- switch (analysis)
+ if (1 == totalNumberWalkers)
{
- case ONESTEP_CHILDREN :
- {
- if (debug)
+ if (DEBUG_WALKER_CREATION)
System.out.println("analysis -- onestep child: " + analysis + ", "
+ compiler.toString());
ai = new ChildWalkerOneStep(lpi);
}
- break;
- case MULTISTEP_CHILDREN :
- if (debug)
- System.out.println("analysis -- multi-step child: " + analysis
- + ", " + compiler.toString());
+ else
+ {
+ if (0 == ~(BIT_CHILD | BIT_PREDICATE | BITS_COUNT))
+ {
+ if (DEBUG_WALKER_CREATION)
+ System.out.println("analysis -- multi-step child: " + analysis
+ + ", " + compiler.toString());
- ai = new ChildWalkerMultiStep(lpi);
- break;
- default :
- ai = new ChildWalker(lpi);
+ ai = new ChildWalkerMultiStep(lpi);
+ }
+ else
+ {
+ ai = new ChildWalker(lpi);
+ }
}
break;
case OpCodes.FROM_DESCENDANTS :
@@ -505,12 +519,16 @@
ai = new ParentWalker(lpi);
break;
case OpCodes.FROM_SELF :
- switch (analysis)
+ if (1 == totalNumberWalkers)
{
- case ONESTEP_SELF :
+ if (DEBUG_WALKER_CREATION)
+ System.out.println("analysis -- SelfWalkerOneStep: " + analysis
+ + ", " + compiler.toString());
+
ai = new SelfWalkerOneStep(lpi);
- break;
- default :
+ }
+ else
+ {
ai = new SelfWalker(lpi);
}
break;
@@ -534,7 +552,6 @@
}
else
{
-
int whatToShow = compiler.getWhatToShow(opPos);
/*
@@ -544,7 +561,6 @@
| NodeFilter.SHOW_ELEMENT
| NodeFilter.SHOW_PROCESSING_INSTRUCTION)));
*/
-
if ((0 == (whatToShow
& (NodeFilter.SHOW_ATTRIBUTE | NodeFilter.SHOW_ELEMENT
| NodeFilter.SHOW_PROCESSING_INSTRUCTION))) ||
(whatToShow == NodeFilter.SHOW_ALL))
@@ -555,7 +571,93 @@
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);
+
+ /**
+ * 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);
+
+ /** Bit is on if the expression is a match pattern. */
+ public static final int BIT_MATCH_PATTERN = (0x00001000 << 19);
+
+ // can't go higher than 19!
}
1.1
xml-xalan/java/src/org/apache/xpath/axes/DescendantIterator.java
Index: DescendantIterator.java
===================================================================
/*
* 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 [EMAIL PROTECTED]
*
* 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.xpath.compiler.Compiler;
import org.apache.xpath.patterns.NodeTest;
import org.apache.xpath.objects.XObject;
import org.apache.xpath.compiler.OpCodes;
import org.w3c.dom.traversal.NodeIterator;
import org.w3c.dom.Node;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.DOMException;
import org.w3c.dom.traversal.NodeFilter;
/**
* <meta name="usage" content="advanced"/>
* This class implements an optimized iterator for
* descendant, descendant-or-self, or "//foo" patterns.
* @see org.apache.xpath.axes.WalkerFactory#newLocPathIterator.
*/
public class DescendantIterator extends LocPathIterator
{
/**
* Create a DescendantIterator object.
*
* @param compiler A reference to the Compiler that contains the op map.
* @param opPos The position within the op map, which contains the
* location path expression for this itterator.
*
* @throws javax.xml.transform.TransformerException
*/
public DescendantIterator(Compiler compiler, int opPos)
throws javax.xml.transform.TransformerException
{
super(compiler, opPos, false);
int ops[] = compiler.getOpMap();
int firstStepPos = compiler.getFirstChildPos(opPos);
int stepType = ops[firstStepPos];
if (OpCodes.FROM_DESCENDANTS_OR_SELF == stepType)
m_orSelf = true;
else if(OpCodes.FROM_ROOT == stepType)
{
m_fromRoot = true;
m_orSelf = true;
firstStepPos += 8;
}
else
m_orSelf = false;
m_nodeTest = new NodeTest();
int whatToShow = compiler.getWhatToShow(firstStepPos);
if ((0 == (whatToShow
& (NodeFilter.SHOW_ATTRIBUTE | NodeFilter.SHOW_ELEMENT
| NodeFilter.SHOW_PROCESSING_INSTRUCTION))) || (whatToShow
== NodeFilter.SHOW_ALL))
m_nodeTest.initNodeTest(whatToShow);
else
{
m_nodeTest.initNodeTest(whatToShow, compiler.getStepNS(firstStepPos),
compiler.getStepLocalName(firstStepPos));
}
}
/**
* Returns the next node in the set and advances the position of the
* iterator in the set. After a NodeIterator is created, the first call
* to nextNode() returns the first node in the set.
*
* @return The next <code>Node</code> in the set being iterated over, or
* <code>null</code> if there are no more members in that set.
*
* @exception DOMException
* INVALID_STATE_ERR: Raised if this method is called after the
* <code>detach</code> method was invoked.
*/
public Node nextNode() throws DOMException
{
// If the cache is on, and the node has already been found, then
// just return from the list.
if ((null != m_cachedNodes)
&& (m_cachedNodes.getCurrentPos() < m_cachedNodes.size()))
{
Node next = m_cachedNodes.nextNode();
this.setCurrentPos(m_cachedNodes.getCurrentPos());
return next;
}
if (m_foundLast)
return null;
Node pos; // our main itteration node.
boolean getSelf;
// Figure out what the start context should be.
// If the m_lastFetched is null at this point we're at the start
// of a fresh iteration.
if (null == m_lastFetched)
{
getSelf = m_orSelf; // true if descendants-or-self.
// The start context can either be the location path context node,
// or the root node.
if (getSelf && m_fromRoot)
{
if(m_context.getNodeType() == Node.DOCUMENT_NODE)
pos = m_context;
else
pos = m_context.getOwnerDocument();
}
else
pos = m_context;
m_startContext = pos;
}
else
{
// if the iterator is not fresh...
pos = m_lastFetched;
getSelf = false; // never process the start node at this point.
}
Node top = m_startContext; // tells us when to stop.
Node next = null;
// non-recursive depth-first traversal.
while (null != pos)
{
if(getSelf)
{
try
{
XObject score = m_nodeTest.execute(m_execContext, pos);
if (NodeTest.SCORE_NONE != score)
{
next = pos;
break;
}
}
catch (TransformerException te)
{
throw new org.apache.xml.utils.WrappedRuntimeException(te);
}
}
else
getSelf = true;
Node nextNode = pos.getFirstChild();
while (null == nextNode)
{
if (top.equals(pos))
break;
nextNode = pos.getNextSibling();
if (null == nextNode)
{
pos = pos.getParentNode();
if ((null == pos) || (top.equals(pos)))
{
nextNode = null;
break;
}
}
}
pos = nextNode;
}
m_lastFetched = next;
if (null != next)
{
if (null != m_cachedNodes)
m_cachedNodes.addElement(next);
m_next++;
return next;
}
else
{
m_foundLast = true;
m_startContext = null;
return null;
}
}
/** The top of the subtree, may not be the same as m_context if "//foo"
pattern. */
private Node m_startContext;
/** The NodeTest for this iterator. */
private NodeTest m_nodeTest;
/** True if this is a descendants-or-self axes. */
private boolean m_orSelf;
/** True if this is a descendants-or-self axes. */
private boolean m_fromRoot;
}