2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 * $Id: WalkerFactory.java 469314 2006-10-30 23:31:59Z minchau $
21 package org.apache.xpath.axes;
23 import org.apache.xalan.res.XSLMessages;
24 import org.apache.xml.dtm.Axis;
25 import org.apache.xml.dtm.DTMFilter;
26 import org.apache.xml.dtm.DTMIterator;
27 import org.apache.xpath.Expression;
28 import org.apache.xpath.compiler.Compiler;
29 import org.apache.xpath.compiler.FunctionTable;
30 import org.apache.xpath.compiler.OpCodes;
31 import org.apache.xpath.compiler.OpMap;
32 import org.apache.xpath.objects.XNumber;
33 import org.apache.xpath.patterns.ContextMatchStepPattern;
34 import org.apache.xpath.patterns.FunctionPattern;
35 import org.apache.xpath.patterns.NodeTest;
36 import org.apache.xpath.patterns.StepPattern;
37 import org.apache.xpath.res.XPATHErrorResources;
40 * This class is both a factory for XPath location path expressions,
41 * which are built from the opcode map output, and an analysis engine
42 * for the location path expressions in order to provide optimization hints.
44 public class WalkerFactory
48 * This method is for building an array of possible levels
49 * where the target element(s) could be found for a match.
50 * @param lpi The owning location path iterator.
51 * @param compiler non-null reference to compiler object that has processed
52 * the XPath operations into an opcode map.
53 * @param stepOpCodePos The opcode position for the step.
55 * @return non-null AxesWalker derivative.
57 * @throws javax.xml.transform.TransformerException
60 static AxesWalker loadOneWalker(
61 WalkingIterator lpi, Compiler compiler, int stepOpCodePos)
62 throws javax.xml.transform.TransformerException
65 AxesWalker firstWalker = null;
66 int stepType = compiler.getOp(stepOpCodePos);
68 if (stepType != OpCodes.ENDOP)
71 // m_axesWalkers = new AxesWalker[1];
72 // As we unwind from the recursion, create the iterators.
73 firstWalker = createDefaultWalker(compiler, stepType, lpi, 0);
75 firstWalker.init(compiler, stepOpCodePos, stepType);
82 * This method is for building an array of possible levels
83 * where the target element(s) could be found for a match.
84 * @param lpi The owning location path iterator object.
85 * @param compiler non-null reference to compiler object that has processed
86 * the XPath operations into an opcode map.
87 * @param stepOpCodePos The opcode position for the step.
88 * @param stepIndex The top-level step index withing the iterator.
90 * @return non-null AxesWalker derivative.
92 * @throws javax.xml.transform.TransformerException
95 static AxesWalker loadWalkers(
96 WalkingIterator lpi, Compiler compiler, int stepOpCodePos, int stepIndex)
97 throws javax.xml.transform.TransformerException
101 AxesWalker firstWalker = null;
102 AxesWalker walker, prevWalker = null;
104 int analysis = analyze(compiler, stepOpCodePos, stepIndex);
106 while (OpCodes.ENDOP != (stepType = compiler.getOp(stepOpCodePos)))
108 walker = createDefaultWalker(compiler, stepOpCodePos, lpi, analysis);
110 walker.init(compiler, stepOpCodePos, stepType);
111 walker.exprSetParent(lpi);
113 // walker.setAnalysis(analysis);
114 if (null == firstWalker)
116 firstWalker = walker;
120 prevWalker.setNextWalker(walker);
121 walker.setPrevWalker(prevWalker);
125 stepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
127 if (stepOpCodePos < 0)
134 public static boolean isSet(int analysis, int bits)
136 return (0 != (analysis & bits));
139 public static void diagnoseIterator(String name, int analysis, Compiler compiler)
141 System.out.println(compiler.toString()+", "+name+", "
142 + Integer.toBinaryString(analysis) + ", "
143 + getAnalysisString(analysis));
147 * Create a new LocPathIterator iterator. The exact type of iterator
148 * returned is based on an analysis of the XPath operations.
150 * @param compiler non-null reference to compiler object that has processed
151 * the XPath operations into an opcode map.
152 * @param opPos The position of the operation code for this itterator.
154 * @return non-null reference to a LocPathIterator or derivative.
156 * @throws javax.xml.transform.TransformerException
158 public static DTMIterator newDTMIterator(
159 Compiler compiler, int opPos,
161 throws javax.xml.transform.TransformerException
164 int firstStepPos = OpMap.getFirstChildPos(opPos);
165 int analysis = analyze(compiler, firstStepPos, 0);
166 boolean isOneStep = isOneStep(analysis);
169 // Is the iteration a one-step attribute pattern (i.e. select="@foo")?
170 if (isOneStep && walksSelfOnly(analysis) &&
171 isWild(analysis) && !hasPredicate(analysis))
173 if (DEBUG_ITERATOR_CREATION)
174 diagnoseIterator("SelfIteratorNoPredicate", analysis, compiler);
176 // Then use a simple iteration of the attributes, with node test
177 // and predicate testing.
178 iter = new SelfIteratorNoPredicate(compiler, opPos, analysis);
180 // Is the iteration exactly one child step?
181 else if (walksChildrenOnly(analysis) && isOneStep)
184 // Does the pattern specify *any* child with no predicate? (i.e. select="child::node()".
185 if (isWild(analysis) && !hasPredicate(analysis))
187 if (DEBUG_ITERATOR_CREATION)
188 diagnoseIterator("ChildIterator", analysis, compiler);
190 // Use simple child iteration without any test.
191 iter = new ChildIterator(compiler, opPos, analysis);
195 if (DEBUG_ITERATOR_CREATION)
196 diagnoseIterator("ChildTestIterator", analysis, compiler);
198 // Else use simple node test iteration with predicate test.
199 iter = new ChildTestIterator(compiler, opPos, analysis);
202 // Is the iteration a one-step attribute pattern (i.e. select="@foo")?
203 else if (isOneStep && walksAttributes(analysis))
205 if (DEBUG_ITERATOR_CREATION)
206 diagnoseIterator("AttributeIterator", analysis, compiler);
208 // Then use a simple iteration of the attributes, with node test
209 // and predicate testing.
210 iter = new AttributeIterator(compiler, opPos, analysis);
212 else if(isOneStep && !walksFilteredList(analysis))
214 if( !walksNamespaces(analysis)
215 && (walksInDocOrder(analysis) || isSet(analysis, BIT_PARENT)))
217 if (false || DEBUG_ITERATOR_CREATION)
218 diagnoseIterator("OneStepIteratorForward", analysis, compiler);
220 // Then use a simple iteration of the attributes, with node test
221 // and predicate testing.
222 iter = new OneStepIteratorForward(compiler, opPos, analysis);
226 if (false || DEBUG_ITERATOR_CREATION)
227 diagnoseIterator("OneStepIterator", analysis, compiler);
229 // Then use a simple iteration of the attributes, with node test
230 // and predicate testing.
231 iter = new OneStepIterator(compiler, opPos, analysis);
235 // Analysis of "//center":
236 // bits: 1001000000001010000000000000011
240 // BIT_DESCENDANT_OR_SELF
241 // It's highly possible that we should have a seperate bit set for
243 // For at least the time being, we can't optimize patterns like
244 // "//table[3]", because this has to be analyzed as
245 // "/descendant-or-self::node()/table[3]" in order for the indexes
247 else if (isOptimizableForDescendantIterator(compiler, firstStepPos, 0)
248 // && getStepCount(analysis) <= 3
249 // && walksDescendants(analysis)
250 // && walksSubtreeOnlyFromRootOrContext(analysis)
253 if (DEBUG_ITERATOR_CREATION)
254 diagnoseIterator("DescendantIterator", analysis, compiler);
256 iter = new DescendantIterator(compiler, opPos, analysis);
260 if(isNaturalDocOrder(compiler, firstStepPos, 0, analysis))
262 if (false || DEBUG_ITERATOR_CREATION)
264 diagnoseIterator("WalkingIterator", analysis, compiler);
267 iter = new WalkingIterator(compiler, opPos, analysis, true);
271 // if (DEBUG_ITERATOR_CREATION)
272 // diagnoseIterator("MatchPatternIterator", analysis, compiler);
274 // return new MatchPatternIterator(compiler, opPos, analysis);
275 if (DEBUG_ITERATOR_CREATION)
276 diagnoseIterator("WalkingIteratorSorted", analysis, compiler);
278 iter = new WalkingIteratorSorted(compiler, opPos, analysis, true);
281 if(iter instanceof LocPathIterator)
282 ((LocPathIterator)iter).setIsTopLevel(isTopLevel);
288 * Special purpose function to see if we can optimize the pattern for
289 * a DescendantIterator.
291 * @param compiler non-null reference to compiler object that has processed
292 * the XPath operations into an opcode map.
293 * @param stepOpCodePos The opcode position for the step.
295 * @return 32 bits as an integer that give information about the location
298 * @throws javax.xml.transform.TransformerException
300 public static int getAxisFromStep(
301 Compiler compiler, int stepOpCodePos)
302 throws javax.xml.transform.TransformerException
305 int stepType = compiler.getOp(stepOpCodePos);
309 case OpCodes.FROM_FOLLOWING :
310 return Axis.FOLLOWING;
311 case OpCodes.FROM_FOLLOWING_SIBLINGS :
312 return Axis.FOLLOWINGSIBLING;
313 case OpCodes.FROM_PRECEDING :
314 return Axis.PRECEDING;
315 case OpCodes.FROM_PRECEDING_SIBLINGS :
316 return Axis.PRECEDINGSIBLING;
317 case OpCodes.FROM_PARENT :
319 case OpCodes.FROM_NAMESPACE :
320 return Axis.NAMESPACE;
321 case OpCodes.FROM_ANCESTORS :
322 return Axis.ANCESTOR;
323 case OpCodes.FROM_ANCESTORS_OR_SELF :
324 return Axis.ANCESTORORSELF;
325 case OpCodes.FROM_ATTRIBUTES :
326 return Axis.ATTRIBUTE;
327 case OpCodes.FROM_ROOT :
329 case OpCodes.FROM_CHILDREN :
331 case OpCodes.FROM_DESCENDANTS_OR_SELF :
332 return Axis.DESCENDANTORSELF;
333 case OpCodes.FROM_DESCENDANTS :
334 return Axis.DESCENDANT;
335 case OpCodes.FROM_SELF :
337 case OpCodes.OP_EXTFUNCTION :
338 case OpCodes.OP_FUNCTION :
339 case OpCodes.OP_GROUP :
340 case OpCodes.OP_VARIABLE :
341 return Axis.FILTEREDLIST;
344 throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
349 * Get a corresponding BIT_XXX from an axis.
350 * @param axis One of Axis.ANCESTOR, etc.
351 * @return One of BIT_ANCESTOR, etc.
353 static public int getAnalysisBitFromAxes(int axis)
355 switch (axis) // Generate new traverser
359 case Axis.ANCESTORORSELF :
360 return BIT_ANCESTOR_OR_SELF;
361 case Axis.ATTRIBUTE :
362 return BIT_ATTRIBUTE;
365 case Axis.DESCENDANT :
366 return BIT_DESCENDANT;
367 case Axis.DESCENDANTORSELF :
368 return BIT_DESCENDANT_OR_SELF;
369 case Axis.FOLLOWING :
370 return BIT_FOLLOWING;
371 case Axis.FOLLOWINGSIBLING :
372 return BIT_FOLLOWING_SIBLING;
373 case Axis.NAMESPACE :
374 case Axis.NAMESPACEDECLS :
375 return BIT_NAMESPACE;
378 case Axis.PRECEDING :
379 return BIT_PRECEDING;
380 case Axis.PRECEDINGSIBLING :
381 return BIT_PRECEDING_SIBLING;
384 case Axis.ALLFROMNODE :
385 return BIT_DESCENDANT_OR_SELF;
386 // case Axis.PRECEDINGANDANCESTOR :
387 case Axis.DESCENDANTSFROMROOT :
389 case Axis.DESCENDANTSORSELFFROMROOT :
390 return BIT_ANY_DESCENDANT_FROM_ROOT;
393 case Axis.FILTEREDLIST :
400 static boolean functionProximateOrContainsProximate(Compiler compiler,
403 int endFunc = opPos + compiler.getOp(opPos + 1) - 1;
404 opPos = OpMap.getFirstChildPos(opPos);
405 int funcID = compiler.getOp(opPos);
406 // System.out.println("funcID: "+funcID);
407 // System.out.println("opPos: "+opPos);
408 // System.out.println("endFunc: "+endFunc);
411 case FunctionTable.FUNC_LAST:
412 case FunctionTable.FUNC_POSITION:
417 for (int p = opPos; p < endFunc; p = compiler.getNextOpPos(p), i++)
419 int innerExprOpPos = p+2;
420 int argOp = compiler.getOp(innerExprOpPos);
421 boolean prox = isProximateInnerExpr(compiler, innerExprOpPos);
430 static boolean isProximateInnerExpr(Compiler compiler, int opPos)
432 int op = compiler.getOp(opPos);
433 int innerExprOpPos = opPos+2;
436 case OpCodes.OP_ARGUMENT:
437 if(isProximateInnerExpr(compiler, innerExprOpPos))
440 case OpCodes.OP_VARIABLE:
441 case OpCodes.OP_NUMBERLIT:
442 case OpCodes.OP_LITERAL:
443 case OpCodes.OP_LOCATIONPATH:
445 case OpCodes.OP_FUNCTION:
446 boolean isProx = functionProximateOrContainsProximate(compiler, opPos);
454 case OpCodes.OP_EQUALS:
455 int leftPos = OpMap.getFirstChildPos(op);
456 int rightPos = compiler.getNextOpPos(leftPos);
457 isProx = isProximateInnerExpr(compiler, leftPos);
460 isProx = isProximateInnerExpr(compiler, rightPos);
465 return true; // be conservative...
471 * Tell if the predicates need to have proximity knowledge.
473 public static boolean mightBeProximate(Compiler compiler, int opPos, int stepType)
474 throws javax.xml.transform.TransformerException
477 boolean mightBeProximate = false;
482 case OpCodes.OP_VARIABLE :
483 case OpCodes.OP_EXTFUNCTION :
484 case OpCodes.OP_FUNCTION :
485 case OpCodes.OP_GROUP :
486 argLen = compiler.getArgLength(opPos);
489 argLen = compiler.getArgLengthOfStep(opPos);
492 int predPos = compiler.getFirstPredicateOpPos(opPos);
495 while (OpCodes.OP_PREDICATE == compiler.getOp(predPos))
499 int innerExprOpPos = predPos+2;
500 int predOp = compiler.getOp(innerExprOpPos);
504 case OpCodes.OP_VARIABLE:
505 return true; // Would need more smarts to tell if this could be a number or not!
506 case OpCodes.OP_LOCATIONPATH:
509 case OpCodes.OP_NUMBER:
510 case OpCodes.OP_NUMBERLIT:
511 return true; // that's all she wrote!
512 case OpCodes.OP_FUNCTION:
514 = functionProximateOrContainsProximate(compiler, innerExprOpPos);
522 case OpCodes.OP_EQUALS:
523 int leftPos = OpMap.getFirstChildPos(innerExprOpPos);
524 int rightPos = compiler.getNextOpPos(leftPos);
525 isProx = isProximateInnerExpr(compiler, leftPos);
528 isProx = isProximateInnerExpr(compiler, rightPos);
533 return true; // be conservative...
536 predPos = compiler.getNextOpPos(predPos);
539 return mightBeProximate;
543 * Special purpose function to see if we can optimize the pattern for
544 * a DescendantIterator.
546 * @param compiler non-null reference to compiler object that has processed
547 * the XPath operations into an opcode map.
548 * @param stepOpCodePos The opcode position for the step.
549 * @param stepIndex The top-level step index withing the iterator.
551 * @return 32 bits as an integer that give information about the location
554 * @throws javax.xml.transform.TransformerException
556 private static boolean isOptimizableForDescendantIterator(
557 Compiler compiler, int stepOpCodePos, int stepIndex)
558 throws javax.xml.transform.TransformerException
563 boolean foundDorDS = false;
564 boolean foundSelf = false;
565 boolean foundDS = false;
567 int nodeTestType = OpCodes.NODETYPE_NODE;
569 while (OpCodes.ENDOP != (stepType = compiler.getOp(stepOpCodePos)))
571 // The DescendantIterator can only do one node test. If there's more
572 // than one, use another iterator.
573 if(nodeTestType != OpCodes.NODETYPE_NODE && nodeTestType != OpCodes.NODETYPE_ROOT)
580 boolean mightBeProximate = mightBeProximate(compiler, stepOpCodePos, stepType);
586 case OpCodes.FROM_FOLLOWING :
587 case OpCodes.FROM_FOLLOWING_SIBLINGS :
588 case OpCodes.FROM_PRECEDING :
589 case OpCodes.FROM_PRECEDING_SIBLINGS :
590 case OpCodes.FROM_PARENT :
591 case OpCodes.OP_VARIABLE :
592 case OpCodes.OP_EXTFUNCTION :
593 case OpCodes.OP_FUNCTION :
594 case OpCodes.OP_GROUP :
595 case OpCodes.FROM_NAMESPACE :
596 case OpCodes.FROM_ANCESTORS :
597 case OpCodes.FROM_ANCESTORS_OR_SELF :
598 case OpCodes.FROM_ATTRIBUTES :
599 case OpCodes.MATCH_ATTRIBUTE :
600 case OpCodes.MATCH_ANY_ANCESTOR :
601 case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
603 case OpCodes.FROM_ROOT :
607 case OpCodes.FROM_CHILDREN :
608 if(!foundDS && !(foundDorDS && foundSelf))
611 case OpCodes.FROM_DESCENDANTS_OR_SELF :
613 case OpCodes.FROM_DESCENDANTS :
618 case OpCodes.FROM_SELF :
624 throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
628 nodeTestType = compiler.getStepTestType(stepOpCodePos);
630 int nextStepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
632 if (nextStepOpCodePos < 0)
635 if(OpCodes.ENDOP != compiler.getOp(nextStepOpCodePos))
637 if(compiler.countPredicates(stepOpCodePos) > 0)
643 stepOpCodePos = nextStepOpCodePos;
650 * Analyze the location path and return 32 bits that give information about
651 * the location path as a whole. See the BIT_XXX constants for meaning about
654 * @param compiler non-null reference to compiler object that has processed
655 * the XPath operations into an opcode map.
656 * @param stepOpCodePos The opcode position for the step.
657 * @param stepIndex The top-level step index withing the iterator.
659 * @return 32 bits as an integer that give information about the location
662 * @throws javax.xml.transform.TransformerException
664 private static int analyze(
665 Compiler compiler, int stepOpCodePos, int stepIndex)
666 throws javax.xml.transform.TransformerException
671 int analysisResult = 0x00000000; // 32 bits of analysis
673 while (OpCodes.ENDOP != (stepType = compiler.getOp(stepOpCodePos)))
677 // String namespace = compiler.getStepNS(stepOpCodePos);
678 // boolean isNSWild = (null != namespace)
679 // ? namespace.equals(NodeTest.WILD) : false;
680 // String localname = compiler.getStepLocalName(stepOpCodePos);
681 // boolean isWild = (null != localname) ? localname.equals(NodeTest.WILD) : false;
682 boolean predAnalysis = analyzePredicate(compiler, stepOpCodePos,
686 analysisResult |= BIT_PREDICATE;
690 case OpCodes.OP_VARIABLE :
691 case OpCodes.OP_EXTFUNCTION :
692 case OpCodes.OP_FUNCTION :
693 case OpCodes.OP_GROUP :
694 analysisResult |= BIT_FILTER;
696 case OpCodes.FROM_ROOT :
697 analysisResult |= BIT_ROOT;
699 case OpCodes.FROM_ANCESTORS :
700 analysisResult |= BIT_ANCESTOR;
702 case OpCodes.FROM_ANCESTORS_OR_SELF :
703 analysisResult |= BIT_ANCESTOR_OR_SELF;
705 case OpCodes.FROM_ATTRIBUTES :
706 analysisResult |= BIT_ATTRIBUTE;
708 case OpCodes.FROM_NAMESPACE :
709 analysisResult |= BIT_NAMESPACE;
711 case OpCodes.FROM_CHILDREN :
712 analysisResult |= BIT_CHILD;
714 case OpCodes.FROM_DESCENDANTS :
715 analysisResult |= BIT_DESCENDANT;
717 case OpCodes.FROM_DESCENDANTS_OR_SELF :
719 // Use a special bit to to make sure we get the right analysis of "//foo".
720 if (2 == stepCount && BIT_ROOT == analysisResult)
722 analysisResult |= BIT_ANY_DESCENDANT_FROM_ROOT;
725 analysisResult |= BIT_DESCENDANT_OR_SELF;
727 case OpCodes.FROM_FOLLOWING :
728 analysisResult |= BIT_FOLLOWING;
730 case OpCodes.FROM_FOLLOWING_SIBLINGS :
731 analysisResult |= BIT_FOLLOWING_SIBLING;
733 case OpCodes.FROM_PRECEDING :
734 analysisResult |= BIT_PRECEDING;
736 case OpCodes.FROM_PRECEDING_SIBLINGS :
737 analysisResult |= BIT_PRECEDING_SIBLING;
739 case OpCodes.FROM_PARENT :
740 analysisResult |= BIT_PARENT;
742 case OpCodes.FROM_SELF :
743 analysisResult |= BIT_SELF;
745 case OpCodes.MATCH_ATTRIBUTE :
746 analysisResult |= (BIT_MATCH_PATTERN | BIT_ATTRIBUTE);
748 case OpCodes.MATCH_ANY_ANCESTOR :
749 analysisResult |= (BIT_MATCH_PATTERN | BIT_ANCESTOR);
751 case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
752 analysisResult |= (BIT_MATCH_PATTERN | BIT_PARENT);
755 throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
759 if (OpCodes.NODETYPE_NODE == compiler.getOp(stepOpCodePos + 3)) // child::node()
761 analysisResult |= BIT_NODETEST_ANY;
764 stepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
766 if (stepOpCodePos < 0)
770 analysisResult |= (stepCount & BITS_COUNT);
772 return analysisResult;
776 * Tell if the given axis goes downword. Bogus name, if you can think of
777 * a better one, please do tell. This really has to do with inverting
779 * @param axis One of Axis.XXX.
780 * @return true if the axis is not a child axis and does not go up from
783 public static boolean isDownwardAxisOfMany(int axis)
785 return ((Axis.DESCENDANTORSELF == axis) ||
786 (Axis.DESCENDANT == axis)
787 || (Axis.FOLLOWING == axis)
788 // || (Axis.FOLLOWINGSIBLING == axis)
789 || (Axis.PRECEDING == axis)
790 // || (Axis.PRECEDINGSIBLING == axis)
795 * Read a <a href="http://www.w3.org/TR/xpath#location-paths">LocationPath</a>
796 * as a generalized match pattern. What this means is that the LocationPath
797 * is read backwards, as a test on a given node, to see if it matches the
798 * criteria of the selection, and ends up at the context node. Essentially,
799 * this is a backwards query from a given node, to find the context node.
800 * <p>So, the selection "foo/daz[2]" is, in non-abreviated expanded syntax,
801 * "self::node()/following-sibling::foo/child::daz[position()=2]".
802 * Taking this as a match pattern for a probable node, it works out to
803 * "self::daz/parent::foo[child::daz[position()=2 and isPrevStepNode()]
804 * precedingSibling::node()[isContextNodeOfLocationPath()]", adding magic
805 * isPrevStepNode and isContextNodeOfLocationPath operations. Predicates in
806 * the location path have to be executed by the following step,
807 * because they have to know the context of their execution.
809 * @param mpi The MatchPatternIterator to which the steps will be attached.
810 * @param compiler The compiler that holds the syntax tree/op map to
812 * @param stepOpCodePos The current op code position within the opmap.
813 * @param stepIndex The top-level step index withing the iterator.
815 * @return A StepPattern object, which may contain relative StepPatterns.
817 * @throws javax.xml.transform.TransformerException
819 static StepPattern loadSteps(
820 MatchPatternIterator mpi, Compiler compiler, int stepOpCodePos,
822 throws javax.xml.transform.TransformerException
824 if (DEBUG_PATTERN_CREATION)
826 System.out.println("================");
827 System.out.println("loadSteps for: "+compiler.getPatternString());
830 StepPattern step = null;
831 StepPattern firstStep = null, prevStep = null;
832 int analysis = analyze(compiler, stepOpCodePos, stepIndex);
834 while (OpCodes.ENDOP != (stepType = compiler.getOp(stepOpCodePos)))
836 step = createDefaultStepPattern(compiler, stepOpCodePos, mpi, analysis,
837 firstStep, prevStep);
839 if (null == firstStep)
846 //prevStep.setNextWalker(step);
847 step.setRelativePathPattern(prevStep);
851 stepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
853 if (stepOpCodePos < 0)
857 int axis = Axis.SELF;
858 int paxis = Axis.SELF;
859 StepPattern tail = step;
860 for (StepPattern pat = step; null != pat;
861 pat = pat.getRelativePathPattern())
863 int nextAxis = pat.getAxis();
864 //int nextPaxis = pat.getPredicateAxis();
867 // The predicate axis can't be moved!!! Test Axes103
868 // pat.setPredicateAxis(paxis);
870 // If we have an attribute or namespace axis that went up, then
871 // it won't find the attribute in the inverse, since the select-to-match
872 // axes are not invertable (an element is a parent of an attribute, but
873 // and attribute is not a child of an element).
874 // If we don't do the magic below, then "@*/ancestor-or-self::*" gets
875 // inverted for match to "self::*/descendant-or-self::@*/parent::node()",
876 // which obviously won't work.
877 // So we will rewrite this as:
878 // "self::*/descendant-or-self::*/attribute::*/parent::node()"
879 // Child has to be rewritten a little differently:
880 // select: "@*/parent::*"
881 // inverted match: "self::*/child::@*/parent::node()"
882 // rewrite: "self::*/attribute::*/parent::node()"
883 // Axes that go down in the select, do not have to have special treatment
884 // in the rewrite. The following inverted match will still not select
886 // select: "@*/child::*"
887 // inverted match: "self::*/parent::@*/parent::node()"
888 // Lovely business, this.
890 int whatToShow = pat.getWhatToShow();
891 if(whatToShow == DTMFilter.SHOW_ATTRIBUTE ||
892 whatToShow == DTMFilter.SHOW_NAMESPACE)
894 int newAxis = (whatToShow == DTMFilter.SHOW_ATTRIBUTE) ?
895 Axis.ATTRIBUTE : Axis.NAMESPACE;
896 if(isDownwardAxisOfMany(axis))
898 StepPattern attrPat = new StepPattern(whatToShow,
901 //newAxis, pat.getPredicateAxis);
902 newAxis, 0); // don't care about the predicate axis
903 XNumber score = pat.getStaticScore();
904 pat.setNamespace(null);
905 pat.setLocalName(NodeTest.WILD);
906 attrPat.setPredicates(pat.getPredicates());
907 pat.setPredicates(null);
908 pat.setWhatToShow(DTMFilter.SHOW_ELEMENT);
909 StepPattern rel = pat.getRelativePathPattern();
910 pat.setRelativePathPattern(attrPat);
911 attrPat.setRelativePathPattern(rel);
912 attrPat.setStaticScore(score);
914 // This is needed to inverse a following pattern, because of the
915 // wacky Xalan rules for following from an attribute. See axes108.
916 // By these rules, following from an attribute is not strictly
918 if(Axis.PRECEDING == pat.getAxis())
919 pat.setAxis(Axis.PRECEDINGANDANCESTOR);
921 else if(Axis.DESCENDANT == pat.getAxis())
922 pat.setAxis(Axis.DESCENDANTORSELF);
926 else if(Axis.CHILD == pat.getAxis())
928 // In this case just change the axis.
929 // pat.setWhatToShow(whatToShow);
930 pat.setAxis(Axis.ATTRIBUTE);
940 StepPattern selfPattern = new ContextMatchStepPattern(axis, paxis);
941 // We need to keep the new nodetest from affecting the score...
942 XNumber score = tail.getStaticScore();
943 tail.setRelativePathPattern(selfPattern);
944 tail.setStaticScore(score);
945 selfPattern.setStaticScore(score);
948 if (DEBUG_PATTERN_CREATION)
950 System.out.println("Done loading steps: "+step.toString());
952 System.out.println("");
954 return step; // start from last pattern?? //firstStep;
958 * Create a StepPattern that is contained within a LocationPath.
961 * @param compiler The compiler that holds the syntax tree/op map to
963 * @param stepOpCodePos The current op code position within the opmap.
964 * @param mpi The MatchPatternIterator to which the steps will be attached.
965 * @param analysis 32 bits of analysis, from which the type of AxesWalker
967 * @param tail The step that is the first step analyzed, but the last
968 * step in the relative match linked list, i.e. the tail.
970 * @param head The step that is the current head of the relative
971 * match step linked list.
974 * @return the head of the list.
976 * @throws javax.xml.transform.TransformerException
978 private static StepPattern createDefaultStepPattern(
979 Compiler compiler, int opPos, MatchPatternIterator mpi,
980 int analysis, StepPattern tail, StepPattern head)
981 throws javax.xml.transform.TransformerException
984 int stepType = compiler.getOp(opPos);
985 boolean simpleInit = false;
986 boolean prevIsOneStepDown = true;
988 int whatToShow = compiler.getWhatToShow(opPos);
989 StepPattern ai = null;
990 int axis, predicateAxis;
994 case OpCodes.OP_VARIABLE :
995 case OpCodes.OP_EXTFUNCTION :
996 case OpCodes.OP_FUNCTION :
997 case OpCodes.OP_GROUP :
998 prevIsOneStepDown = false;
1004 case OpCodes.OP_VARIABLE :
1005 case OpCodes.OP_EXTFUNCTION :
1006 case OpCodes.OP_FUNCTION :
1007 case OpCodes.OP_GROUP :
1008 expr = compiler.compile(opPos);
1011 expr = compiler.compile(opPos + 2);
1014 axis = Axis.FILTEREDLIST;
1015 predicateAxis = Axis.FILTEREDLIST;
1016 ai = new FunctionPattern(expr, axis, predicateAxis);
1019 case OpCodes.FROM_ROOT :
1020 whatToShow = DTMFilter.SHOW_DOCUMENT
1021 | DTMFilter.SHOW_DOCUMENT_FRAGMENT;
1024 predicateAxis = Axis.ROOT;
1025 ai = new StepPattern(DTMFilter.SHOW_DOCUMENT |
1026 DTMFilter.SHOW_DOCUMENT_FRAGMENT,
1027 axis, predicateAxis);
1029 case OpCodes.FROM_ATTRIBUTES :
1030 whatToShow = DTMFilter.SHOW_ATTRIBUTE;
1032 predicateAxis = Axis.ATTRIBUTE;
1033 // ai = new StepPattern(whatToShow, Axis.SELF, Axis.SELF);
1035 case OpCodes.FROM_NAMESPACE :
1036 whatToShow = DTMFilter.SHOW_NAMESPACE;
1038 predicateAxis = Axis.NAMESPACE;
1039 // ai = new StepPattern(whatToShow, axis, predicateAxis);
1041 case OpCodes.FROM_ANCESTORS :
1042 axis = Axis.DESCENDANT;
1043 predicateAxis = Axis.ANCESTOR;
1045 case OpCodes.FROM_CHILDREN :
1047 predicateAxis = Axis.CHILD;
1049 case OpCodes.FROM_ANCESTORS_OR_SELF :
1050 axis = Axis.DESCENDANTORSELF;
1051 predicateAxis = Axis.ANCESTORORSELF;
1053 case OpCodes.FROM_SELF :
1055 predicateAxis = Axis.SELF;
1057 case OpCodes.FROM_PARENT :
1059 predicateAxis = Axis.PARENT;
1061 case OpCodes.FROM_PRECEDING_SIBLINGS :
1062 axis = Axis.FOLLOWINGSIBLING;
1063 predicateAxis = Axis.PRECEDINGSIBLING;
1065 case OpCodes.FROM_PRECEDING :
1066 axis = Axis.FOLLOWING;
1067 predicateAxis = Axis.PRECEDING;
1069 case OpCodes.FROM_FOLLOWING_SIBLINGS :
1070 axis = Axis.PRECEDINGSIBLING;
1071 predicateAxis = Axis.FOLLOWINGSIBLING;
1073 case OpCodes.FROM_FOLLOWING :
1074 axis = Axis.PRECEDING;
1075 predicateAxis = Axis.FOLLOWING;
1077 case OpCodes.FROM_DESCENDANTS_OR_SELF :
1078 axis = Axis.ANCESTORORSELF;
1079 predicateAxis = Axis.DESCENDANTORSELF;
1081 case OpCodes.FROM_DESCENDANTS :
1082 axis = Axis.ANCESTOR;
1083 predicateAxis = Axis.DESCENDANT;
1086 throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
1091 whatToShow = compiler.getWhatToShow(opPos); // %REVIEW%
1092 ai = new StepPattern(whatToShow, compiler.getStepNS(opPos),
1093 compiler.getStepLocalName(opPos),
1094 axis, predicateAxis);
1097 if (false || DEBUG_PATTERN_CREATION)
1099 System.out.print("new step: "+ ai);
1100 System.out.print(", axis: " + Axis.getNames(ai.getAxis()));
1101 System.out.print(", predAxis: " + Axis.getNames(ai.getAxis()));
1102 System.out.print(", what: ");
1103 System.out.print(" ");
1104 ai.debugWhatToShow(ai.getWhatToShow());
1107 int argLen = compiler.getFirstPredicateOpPos(opPos);
1109 ai.setPredicates(compiler.getCompiledPredicates(argLen));
1115 * Analyze a step and give information about it's predicates. Right now this
1116 * just returns true or false if the step has a predicate.
1118 * @param compiler non-null reference to compiler object that has processed
1119 * the XPath operations into an opcode map.
1120 * @param opPos The opcode position for the step.
1121 * @param stepType The type of step, one of OP_GROUP, etc.
1123 * @return true if step has a predicate.
1125 * @throws javax.xml.transform.TransformerException
1127 static boolean analyzePredicate(Compiler compiler, int opPos, int stepType)
1128 throws javax.xml.transform.TransformerException
1135 case OpCodes.OP_VARIABLE :
1136 case OpCodes.OP_EXTFUNCTION :
1137 case OpCodes.OP_FUNCTION :
1138 case OpCodes.OP_GROUP :
1139 argLen = compiler.getArgLength(opPos);
1142 argLen = compiler.getArgLengthOfStep(opPos);
1145 int pos = compiler.getFirstPredicateOpPos(opPos);
1146 int nPredicates = compiler.countPredicates(pos);
1148 return (nPredicates > 0) ? true : false;
1152 * Create the proper Walker from the axes type.
1154 * @param compiler non-null reference to compiler object that has processed
1155 * the XPath operations into an opcode map.
1156 * @param opPos The opcode position for the step.
1157 * @param lpi The owning location path iterator.
1158 * @param analysis 32 bits of analysis, from which the type of AxesWalker
1159 * may be influenced.
1161 * @return non-null reference to AxesWalker derivative.
1162 * @throws RuntimeException if the input is bad.
1164 private static AxesWalker createDefaultWalker(Compiler compiler, int opPos,
1165 WalkingIterator lpi, int analysis)
1168 AxesWalker ai = null;
1169 int stepType = compiler.getOp(opPos);
1172 System.out.println("0: "+compiler.getOp(opPos));
1173 System.out.println("1: "+compiler.getOp(opPos+1));
1174 System.out.println("2: "+compiler.getOp(opPos+2));
1175 System.out.println("3: "+compiler.getOp(opPos+3));
1176 System.out.println("4: "+compiler.getOp(opPos+4));
1177 System.out.println("5: "+compiler.getOp(opPos+5));
1179 boolean simpleInit = false;
1180 int totalNumberWalkers = (analysis & BITS_COUNT);
1181 boolean prevIsOneStepDown = true;
1185 case OpCodes.OP_VARIABLE :
1186 case OpCodes.OP_EXTFUNCTION :
1187 case OpCodes.OP_FUNCTION :
1188 case OpCodes.OP_GROUP :
1189 prevIsOneStepDown = false;
1191 if (DEBUG_WALKER_CREATION)
1192 System.out.println("new walker: FilterExprWalker: " + analysis
1193 + ", " + compiler.toString());
1195 ai = new FilterExprWalker(lpi);
1198 case OpCodes.FROM_ROOT :
1199 ai = new AxesWalker(lpi, Axis.ROOT);
1201 case OpCodes.FROM_ANCESTORS :
1202 prevIsOneStepDown = false;
1203 ai = new ReverseAxesWalker(lpi, Axis.ANCESTOR);
1205 case OpCodes.FROM_ANCESTORS_OR_SELF :
1206 prevIsOneStepDown = false;
1207 ai = new ReverseAxesWalker(lpi, Axis.ANCESTORORSELF);
1209 case OpCodes.FROM_ATTRIBUTES :
1210 ai = new AxesWalker(lpi, Axis.ATTRIBUTE);
1212 case OpCodes.FROM_NAMESPACE :
1213 ai = new AxesWalker(lpi, Axis.NAMESPACE);
1215 case OpCodes.FROM_CHILDREN :
1216 ai = new AxesWalker(lpi, Axis.CHILD);
1218 case OpCodes.FROM_DESCENDANTS :
1219 prevIsOneStepDown = false;
1220 ai = new AxesWalker(lpi, Axis.DESCENDANT);
1222 case OpCodes.FROM_DESCENDANTS_OR_SELF :
1223 prevIsOneStepDown = false;
1224 ai = new AxesWalker(lpi, Axis.DESCENDANTORSELF);
1226 case OpCodes.FROM_FOLLOWING :
1227 prevIsOneStepDown = false;
1228 ai = new AxesWalker(lpi, Axis.FOLLOWING);
1230 case OpCodes.FROM_FOLLOWING_SIBLINGS :
1231 prevIsOneStepDown = false;
1232 ai = new AxesWalker(lpi, Axis.FOLLOWINGSIBLING);
1234 case OpCodes.FROM_PRECEDING :
1235 prevIsOneStepDown = false;
1236 ai = new ReverseAxesWalker(lpi, Axis.PRECEDING);
1238 case OpCodes.FROM_PRECEDING_SIBLINGS :
1239 prevIsOneStepDown = false;
1240 ai = new ReverseAxesWalker(lpi, Axis.PRECEDINGSIBLING);
1242 case OpCodes.FROM_PARENT :
1243 prevIsOneStepDown = false;
1244 ai = new ReverseAxesWalker(lpi, Axis.PARENT);
1246 case OpCodes.FROM_SELF :
1247 ai = new AxesWalker(lpi, Axis.SELF);
1250 throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
1256 ai.initNodeTest(DTMFilter.SHOW_ALL);
1260 int whatToShow = compiler.getWhatToShow(opPos);
1263 System.out.print("construct: ");
1264 NodeTest.debugWhatToShow(whatToShow);
1265 System.out.println("or stuff: "+(whatToShow & (DTMFilter.SHOW_ATTRIBUTE
1266 | DTMFilter.SHOW_ELEMENT
1267 | DTMFilter.SHOW_PROCESSING_INSTRUCTION)));
1269 if ((0 == (whatToShow
1270 & (DTMFilter.SHOW_ATTRIBUTE | DTMFilter.SHOW_NAMESPACE | DTMFilter.SHOW_ELEMENT
1271 | DTMFilter.SHOW_PROCESSING_INSTRUCTION))) || (whatToShow == DTMFilter.SHOW_ALL))
1272 ai.initNodeTest(whatToShow);
1275 ai.initNodeTest(whatToShow, compiler.getStepNS(opPos),
1276 compiler.getStepLocalName(opPos));
1283 public static String getAnalysisString(int analysis)
1285 StringBuffer buf = new StringBuffer();
1286 buf.append("count: "+getStepCount(analysis)+" ");
1287 if((analysis & BIT_NODETEST_ANY) != 0)
1289 buf.append("NTANY|");
1291 if((analysis & BIT_PREDICATE) != 0)
1293 buf.append("PRED|");
1295 if((analysis & BIT_ANCESTOR) != 0)
1299 if((analysis & BIT_ANCESTOR_OR_SELF) != 0)
1301 buf.append("ANCOS|");
1303 if((analysis & BIT_ATTRIBUTE) != 0)
1305 buf.append("ATTR|");
1307 if((analysis & BIT_CHILD) != 0)
1311 if((analysis & BIT_DESCENDANT) != 0)
1313 buf.append("DESC|");
1315 if((analysis & BIT_DESCENDANT_OR_SELF) != 0)
1317 buf.append("DESCOS|");
1319 if((analysis & BIT_FOLLOWING) != 0)
1323 if((analysis & BIT_FOLLOWING_SIBLING) != 0)
1325 buf.append("FOLS|");
1327 if((analysis & BIT_NAMESPACE) != 0)
1331 if((analysis & BIT_PARENT) != 0)
1335 if((analysis & BIT_PRECEDING) != 0)
1337 buf.append("PREC|");
1339 if((analysis & BIT_PRECEDING_SIBLING) != 0)
1341 buf.append("PRECS|");
1343 if((analysis & BIT_SELF) != 0)
1347 if((analysis & BIT_FILTER) != 0)
1351 if((analysis & BIT_ROOT) != 0)
1355 return buf.toString();
1358 /** Set to true for diagnostics about walker creation */
1359 static final boolean DEBUG_PATTERN_CREATION = false;
1361 /** Set to true for diagnostics about walker creation */
1362 static final boolean DEBUG_WALKER_CREATION = false;
1364 /** Set to true for diagnostics about iterator creation */
1365 static final boolean DEBUG_ITERATOR_CREATION = false;
1367 public static boolean hasPredicate(int analysis)
1369 return (0 != (analysis & BIT_PREDICATE));
1372 public static boolean isWild(int analysis)
1374 return (0 != (analysis & BIT_NODETEST_ANY));
1377 public static boolean walksAncestors(int analysis)
1379 return isSet(analysis, BIT_ANCESTOR | BIT_ANCESTOR_OR_SELF);
1382 public static boolean walksAttributes(int analysis)
1384 return (0 != (analysis & BIT_ATTRIBUTE));
1387 public static boolean walksNamespaces(int analysis)
1389 return (0 != (analysis & BIT_NAMESPACE));
1392 public static boolean walksChildren(int analysis)
1394 return (0 != (analysis & BIT_CHILD));
1397 public static boolean walksDescendants(int analysis)
1399 return isSet(analysis, BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF);
1402 public static boolean walksSubtree(int analysis)
1404 return isSet(analysis, BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF | BIT_CHILD);
1407 public static boolean walksSubtreeOnlyMaybeAbsolute(int analysis)
1409 return walksSubtree(analysis)
1410 && !walksExtraNodes(analysis)
1411 && !walksUp(analysis)
1412 && !walksSideways(analysis)
1416 public static boolean walksSubtreeOnly(int analysis)
1418 return walksSubtreeOnlyMaybeAbsolute(analysis)
1419 && !isAbsolute(analysis)
1423 public static boolean walksFilteredList(int analysis)
1425 return isSet(analysis, BIT_FILTER);
1428 public static boolean walksSubtreeOnlyFromRootOrContext(int analysis)
1430 return walksSubtree(analysis)
1431 && !walksExtraNodes(analysis)
1432 && !walksUp(analysis)
1433 && !walksSideways(analysis)
1434 && !isSet(analysis, BIT_FILTER)
1438 public static boolean walksInDocOrder(int analysis)
1440 return (walksSubtreeOnlyMaybeAbsolute(analysis)
1441 || walksExtraNodesOnly(analysis)
1442 || walksFollowingOnlyMaybeAbsolute(analysis))
1443 && !isSet(analysis, BIT_FILTER)
1447 public static boolean walksFollowingOnlyMaybeAbsolute(int analysis)
1449 return isSet(analysis, BIT_SELF | BIT_FOLLOWING_SIBLING | BIT_FOLLOWING)
1450 && !walksSubtree(analysis)
1451 && !walksUp(analysis)
1452 && !walksSideways(analysis)
1456 public static boolean walksUp(int analysis)
1458 return isSet(analysis, BIT_PARENT | BIT_ANCESTOR | BIT_ANCESTOR_OR_SELF);
1461 public static boolean walksSideways(int analysis)
1463 return isSet(analysis, BIT_FOLLOWING | BIT_FOLLOWING_SIBLING |
1464 BIT_PRECEDING | BIT_PRECEDING_SIBLING);
1467 public static boolean walksExtraNodes(int analysis)
1469 return isSet(analysis, BIT_NAMESPACE | BIT_ATTRIBUTE);
1472 public static boolean walksExtraNodesOnly(int analysis)
1474 return walksExtraNodes(analysis)
1475 && !isSet(analysis, BIT_SELF)
1476 && !walksSubtree(analysis)
1477 && !walksUp(analysis)
1478 && !walksSideways(analysis)
1479 && !isAbsolute(analysis)
1483 public static boolean isAbsolute(int analysis)
1485 return isSet(analysis, BIT_ROOT | BIT_FILTER);
1488 public static boolean walksChildrenOnly(int analysis)
1490 return walksChildren(analysis)
1491 && !isSet(analysis, BIT_SELF)
1492 && !walksExtraNodes(analysis)
1493 && !walksDescendants(analysis)
1494 && !walksUp(analysis)
1495 && !walksSideways(analysis)
1496 && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT))
1500 public static boolean walksChildrenAndExtraAndSelfOnly(int analysis)
1502 return walksChildren(analysis)
1503 && !walksDescendants(analysis)
1504 && !walksUp(analysis)
1505 && !walksSideways(analysis)
1506 && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT))
1510 public static boolean walksDescendantsAndExtraAndSelfOnly(int analysis)
1512 return !walksChildren(analysis)
1513 && walksDescendants(analysis)
1514 && !walksUp(analysis)
1515 && !walksSideways(analysis)
1516 && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT))
1520 public static boolean walksSelfOnly(int analysis)
1522 return isSet(analysis, BIT_SELF)
1523 && !walksSubtree(analysis)
1524 && !walksUp(analysis)
1525 && !walksSideways(analysis)
1526 && !isAbsolute(analysis)
1531 public static boolean walksUpOnly(int analysis)
1533 return !walksSubtree(analysis)
1534 && walksUp(analysis)
1535 && !walksSideways(analysis)
1536 && !isAbsolute(analysis)
1540 public static boolean walksDownOnly(int analysis)
1542 return walksSubtree(analysis)
1543 && !walksUp(analysis)
1544 && !walksSideways(analysis)
1545 && !isAbsolute(analysis)
1549 public static boolean walksDownExtraOnly(int analysis)
1551 return walksSubtree(analysis) && walksExtraNodes(analysis)
1552 && !walksUp(analysis)
1553 && !walksSideways(analysis)
1554 && !isAbsolute(analysis)
1558 public static boolean canSkipSubtrees(int analysis)
1560 return isSet(analysis, BIT_CHILD) | walksSideways(analysis);
1563 public static boolean canCrissCross(int analysis)
1565 // This could be done faster. Coded for clarity.
1566 if(walksSelfOnly(analysis))
1568 else if(walksDownOnly(analysis) && !canSkipSubtrees(analysis))
1570 else if(walksChildrenAndExtraAndSelfOnly(analysis))
1572 else if(walksDescendantsAndExtraAndSelfOnly(analysis))
1574 else if(walksUpOnly(analysis))
1576 else if(walksExtraNodesOnly(analysis))
1578 else if(walksSubtree(analysis)
1579 && (walksSideways(analysis)
1580 || walksUp(analysis)
1581 || canSkipSubtrees(analysis)))
1588 * Tell if the pattern can be 'walked' with the iteration steps in natural
1589 * document order, without duplicates.
1591 * @param analysis The general analysis of the pattern.
1593 * @return true if the walk can be done in natural order.
1595 * @throws javax.xml.transform.TransformerException
1597 static public boolean isNaturalDocOrder(int analysis)
1599 if(canCrissCross(analysis) || isSet(analysis, BIT_NAMESPACE) ||
1600 walksFilteredList(analysis))
1603 if(walksInDocOrder(analysis))
1610 * Tell if the pattern can be 'walked' with the iteration steps in natural
1611 * document order, without duplicates.
1613 * @param compiler non-null reference to compiler object that has processed
1614 * the XPath operations into an opcode map.
1615 * @param stepOpCodePos The opcode position for the step.
1616 * @param stepIndex The top-level step index withing the iterator.
1617 * @param analysis The general analysis of the pattern.
1619 * @return true if the walk can be done in natural order.
1621 * @throws javax.xml.transform.TransformerException
1623 private static boolean isNaturalDocOrder(
1624 Compiler compiler, int stepOpCodePos, int stepIndex, int analysis)
1625 throws javax.xml.transform.TransformerException
1627 if(canCrissCross(analysis))
1630 // Namespaces can present some problems, so just punt if we're looking for
1632 if(isSet(analysis, BIT_NAMESPACE))
1635 // The following, preceding, following-sibling, and preceding sibling can
1636 // be found in doc order if we get to this point, but if they occur
1637 // together, they produce
1638 // duplicates, so it's better for us to eliminate this case so we don't
1639 // have to check for duplicates during runtime if we're using a
1641 if(isSet(analysis, BIT_FOLLOWING | BIT_FOLLOWING_SIBLING) &&
1642 isSet(analysis, BIT_PRECEDING | BIT_PRECEDING_SIBLING))
1645 // OK, now we have to check for select="@*/axis::*" patterns, which
1646 // can also cause duplicates to happen. But select="axis*/@::*" patterns
1647 // are OK, as are select="@foo/axis::*" patterns.
1648 // Unfortunately, we can't do this just via the analysis bits.
1652 boolean foundWildAttribute = false;
1654 // Steps that can traverse anything other than down a
1655 // subtree or that can produce duplicates when used in
1656 // combonation are counted with this variable.
1657 int potentialDuplicateMakingStepCount = 0;
1659 while (OpCodes.ENDOP != (stepType = compiler.getOp(stepOpCodePos)))
1665 case OpCodes.FROM_ATTRIBUTES :
1666 case OpCodes.MATCH_ATTRIBUTE :
1667 if(foundWildAttribute) // Maybe not needed, but be safe.
1670 // This doesn't seem to work as a test for wild card. Hmph.
1671 // int nodeTestType = compiler.getStepTestType(stepOpCodePos);
1673 String localName = compiler.getStepLocalName(stepOpCodePos);
1674 // System.err.println("localName: "+localName);
1675 if(localName.equals("*"))
1677 foundWildAttribute = true;
1680 case OpCodes.FROM_FOLLOWING :
1681 case OpCodes.FROM_FOLLOWING_SIBLINGS :
1682 case OpCodes.FROM_PRECEDING :
1683 case OpCodes.FROM_PRECEDING_SIBLINGS :
1684 case OpCodes.FROM_PARENT :
1685 case OpCodes.OP_VARIABLE :
1686 case OpCodes.OP_EXTFUNCTION :
1687 case OpCodes.OP_FUNCTION :
1688 case OpCodes.OP_GROUP :
1689 case OpCodes.FROM_NAMESPACE :
1690 case OpCodes.FROM_ANCESTORS :
1691 case OpCodes.FROM_ANCESTORS_OR_SELF :
1692 case OpCodes.MATCH_ANY_ANCESTOR :
1693 case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
1694 case OpCodes.FROM_DESCENDANTS_OR_SELF :
1695 case OpCodes.FROM_DESCENDANTS :
1696 if(potentialDuplicateMakingStepCount > 0)
1698 potentialDuplicateMakingStepCount++;
1699 case OpCodes.FROM_ROOT :
1700 case OpCodes.FROM_CHILDREN :
1701 case OpCodes.FROM_SELF :
1702 if(foundWildAttribute)
1706 throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
1710 int nextStepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
1712 if (nextStepOpCodePos < 0)
1715 stepOpCodePos = nextStepOpCodePos;
1721 public static boolean isOneStep(int analysis)
1723 return (analysis & BITS_COUNT) == 0x00000001;
1726 public static int getStepCount(int analysis)
1728 return (analysis & BITS_COUNT);
1732 * First 8 bits are the number of top-level location steps. Hopefully
1733 * there will never be more that 255 location steps!!!
1735 public static final int BITS_COUNT = 0x000000FF;
1737 /** 4 bits are reserved for future use. */
1738 public static final int BITS_RESERVED = 0x00000F00;
1740 /** Bit is on if the expression contains a top-level predicate. */
1741 public static final int BIT_PREDICATE = (0x00001000);
1743 /** Bit is on if any of the walkers contain an ancestor step. */
1744 public static final int BIT_ANCESTOR = (0x00001000 << 1);
1746 /** Bit is on if any of the walkers contain an ancestor-or-self step. */
1747 public static final int BIT_ANCESTOR_OR_SELF = (0x00001000 << 2);
1749 /** Bit is on if any of the walkers contain an attribute step. */
1750 public static final int BIT_ATTRIBUTE = (0x00001000 << 3);
1752 /** Bit is on if any of the walkers contain a child step. */
1753 public static final int BIT_CHILD = (0x00001000 << 4);
1755 /** Bit is on if any of the walkers contain a descendant step. */
1756 public static final int BIT_DESCENDANT = (0x00001000 << 5);
1758 /** Bit is on if any of the walkers contain a descendant-or-self step. */
1759 public static final int BIT_DESCENDANT_OR_SELF = (0x00001000 << 6);
1761 /** Bit is on if any of the walkers contain a following step. */
1762 public static final int BIT_FOLLOWING = (0x00001000 << 7);
1764 /** Bit is on if any of the walkers contain a following-sibiling step. */
1765 public static final int BIT_FOLLOWING_SIBLING = (0x00001000 << 8);
1767 /** Bit is on if any of the walkers contain a namespace step. */
1768 public static final int BIT_NAMESPACE = (0x00001000 << 9);
1770 /** Bit is on if any of the walkers contain a parent step. */
1771 public static final int BIT_PARENT = (0x00001000 << 10);
1773 /** Bit is on if any of the walkers contain a preceding step. */
1774 public static final int BIT_PRECEDING = (0x00001000 << 11);
1776 /** Bit is on if any of the walkers contain a preceding-sibling step. */
1777 public static final int BIT_PRECEDING_SIBLING = (0x00001000 << 12);
1779 /** Bit is on if any of the walkers contain a self step. */
1780 public static final int BIT_SELF = (0x00001000 << 13);
1783 * Bit is on if any of the walkers contain a filter (i.e. id(), extension
1784 * function, etc.) step.
1786 public static final int BIT_FILTER = (0x00001000 << 14);
1788 /** Bit is on if any of the walkers contain a root step. */
1789 public static final int BIT_ROOT = (0x00001000 << 15);
1792 * If any of these bits are on, the expression may likely traverse outside
1793 * the given subtree.
1795 public static final int BITMASK_TRAVERSES_OUTSIDE_SUBTREE = (BIT_NAMESPACE // ??
1796 | BIT_PRECEDING_SIBLING
1798 | BIT_FOLLOWING_SIBLING
1800 | BIT_PARENT // except parent of attrs.
1801 | BIT_ANCESTOR_OR_SELF
1807 * Bit is on if any of the walkers can go backwards in document
1808 * order from the context node.
1810 public static final int BIT_BACKWARDS_SELF = (0x00001000 << 16);
1812 /** Found "//foo" pattern */
1813 public static final int BIT_ANY_DESCENDANT_FROM_ROOT = (0x00001000 << 17);
1816 * Bit is on if any of the walkers contain an node() test. This is
1817 * really only useful if the count is 1.
1819 public static final int BIT_NODETEST_ANY = (0x00001000 << 18);
1821 // can't go higher than 18!
1823 /** Bit is on if the expression is a match pattern. */
1824 public static final int BIT_MATCH_PATTERN = (0x00001000 << 19);