📄 walkerfactory.java
字号:
/* * Copyright 1999-2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* * $Id: WalkerFactory.java,v 1.2.4.1 2005/09/10 03:42:19 jeffsuttor Exp $ */package com.sun.org.apache.xpath.internal.axes;import com.sun.org.apache.xalan.internal.res.XSLMessages;import com.sun.org.apache.xml.internal.dtm.Axis;import com.sun.org.apache.xml.internal.dtm.DTMFilter;import com.sun.org.apache.xml.internal.dtm.DTMIterator;import com.sun.org.apache.xpath.internal.Expression;import com.sun.org.apache.xpath.internal.compiler.Compiler;import com.sun.org.apache.xpath.internal.compiler.FunctionTable;import com.sun.org.apache.xpath.internal.compiler.OpCodes;import com.sun.org.apache.xpath.internal.objects.XNumber;import com.sun.org.apache.xpath.internal.patterns.ContextMatchStepPattern;import com.sun.org.apache.xpath.internal.patterns.FunctionPattern;import com.sun.org.apache.xpath.internal.patterns.NodeTest;import com.sun.org.apache.xpath.internal.patterns.StepPattern;import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;/** * 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{ /** * This method is for building an array of possible levels * where the target element(s) could be found for a match. * @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 * @xsl.usage advanced */ static AxesWalker loadOneWalker( WalkingIterator lpi, Compiler compiler, int stepOpCodePos) throws javax.xml.transform.TransformerException { AxesWalker firstWalker = null; int stepType = compiler.getOp(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; } /** * This method is for building an array of possible levels * where the target element(s) could be found for a match. * @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 * @xsl.usage advanced */ static AxesWalker loadWalkers( WalkingIterator lpi, Compiler compiler, int stepOpCodePos, int stepIndex) throws javax.xml.transform.TransformerException { int stepType; AxesWalker firstWalker = null; AxesWalker walker, prevWalker = null; int analysis = analyze(compiler, stepOpCodePos, stepIndex); while (OpCodes.ENDOP != (stepType = compiler.getOp(stepOpCodePos))) { walker = createDefaultWalker(compiler, stepOpCodePos, lpi, analysis); walker.init(compiler, stepOpCodePos, stepType); walker.exprSetParent(lpi); // walker.setAnalysis(analysis); if (null == firstWalker) { firstWalker = walker; } else { prevWalker.setNextWalker(walker); walker.setPrevWalker(prevWalker); } prevWalker = walker; stepOpCodePos = compiler.getNextStepPos(stepOpCodePos); if (stepOpCodePos < 0) break; } return firstWalker; } public static boolean isSet(int analysis, int bits) { return (0 != (analysis & bits)); } public static void diagnoseIterator(String name, int analysis, Compiler compiler) { System.out.println(compiler.toString()+", "+name+", " + Integer.toBinaryString(analysis) + ", " + getAnalysisString(analysis)); } /** * Create a new LocPathIterator iterator. The exact type of iterator * returned is based on an analysis of the XPath operations. * * @param compiler non-null reference to compiler object that has processed * the XPath operations into an opcode map. * @param opPos The position of the operation code for this itterator. * * @return non-null reference to a LocPathIterator or derivative. * * @throws javax.xml.transform.TransformerException */ public static DTMIterator newDTMIterator( Compiler compiler, int opPos, boolean isTopLevel) throws javax.xml.transform.TransformerException { int firstStepPos = compiler.getFirstChildPos(opPos); int analysis = analyze(compiler, firstStepPos, 0); boolean isOneStep = isOneStep(analysis); DTMIterator iter; // Is the iteration a one-step attribute pattern (i.e. select="@foo")? if (isOneStep && walksSelfOnly(analysis) && isWild(analysis) && !hasPredicate(analysis)) { if (DEBUG_ITERATOR_CREATION) diagnoseIterator("SelfIteratorNoPredicate", analysis, compiler); // Then use a simple iteration of the attributes, with node test // and predicate testing. iter = new SelfIteratorNoPredicate(compiler, opPos, analysis); } // Is the iteration exactly one child step? else if (walksChildrenOnly(analysis) && isOneStep) { // Does the pattern specify *any* child with no predicate? (i.e. select="child::node()". if (isWild(analysis) && !hasPredicate(analysis)) { if (DEBUG_ITERATOR_CREATION) diagnoseIterator("ChildIterator", analysis, compiler); // Use simple child iteration without any test. iter = new ChildIterator(compiler, opPos, analysis); } else { if (DEBUG_ITERATOR_CREATION) diagnoseIterator("ChildTestIterator", analysis, compiler); // Else use simple node test iteration with predicate test. iter = new ChildTestIterator(compiler, opPos, analysis); } } // Is the iteration a one-step attribute pattern (i.e. select="@foo")? else if (isOneStep && walksAttributes(analysis)) { if (DEBUG_ITERATOR_CREATION) diagnoseIterator("AttributeIterator", analysis, compiler); // Then use a simple iteration of the attributes, with node test // and predicate testing. iter = new AttributeIterator(compiler, opPos, analysis); } else if(isOneStep && !walksFilteredList(analysis)) { if( !walksNamespaces(analysis) && (walksInDocOrder(analysis) || isSet(analysis, BIT_PARENT))) { if (false || DEBUG_ITERATOR_CREATION) diagnoseIterator("OneStepIteratorForward", analysis, compiler); // Then use a simple iteration of the attributes, with node test // and predicate testing. iter = new OneStepIteratorForward(compiler, opPos, analysis); } else { if (false || DEBUG_ITERATOR_CREATION) diagnoseIterator("OneStepIterator", analysis, compiler); // Then use a simple iteration of the attributes, with node test // and predicate testing. iter = new OneStepIterator(compiler, opPos, analysis); } } // Analysis of "//center": // bits: 1001000000001010000000000000011 // count: 3 // root // child:node() // BIT_DESCENDANT_OR_SELF // It's highly possible that we should have a seperate bit set for // "//foo" patterns. // For at least the time being, we can't optimize patterns like // "//table[3]", because this has to be analyzed as // "/descendant-or-self::node()/table[3]" in order for the indexes // to work right. else if (isOptimizableForDescendantIterator(compiler, firstStepPos, 0) // && getStepCount(analysis) <= 3 // && walksDescendants(analysis) // && walksSubtreeOnlyFromRootOrContext(analysis) ) { if (DEBUG_ITERATOR_CREATION) diagnoseIterator("DescendantIterator", analysis, compiler); iter = new DescendantIterator(compiler, opPos, analysis); } else { if(isNaturalDocOrder(compiler, firstStepPos, 0, analysis)) { if (false || DEBUG_ITERATOR_CREATION) { diagnoseIterator("WalkingIterator", analysis, compiler); } iter = new WalkingIterator(compiler, opPos, analysis, true); } else {// if (DEBUG_ITERATOR_CREATION)// diagnoseIterator("MatchPatternIterator", analysis, compiler);//// return new MatchPatternIterator(compiler, opPos, analysis); if (DEBUG_ITERATOR_CREATION) diagnoseIterator("WalkingIteratorSorted", analysis, compiler); iter = new WalkingIteratorSorted(compiler, opPos, analysis, true); } } if(iter instanceof LocPathIterator) ((LocPathIterator)iter).setIsTopLevel(isTopLevel); return iter; } /** * Special purpose function to see if we can optimize the pattern for * a DescendantIterator. * * @param compiler non-null reference to compiler object that has processed * the XPath operations into an opcode map. * @param stepOpCodePos The opcode position for the step. * * @return 32 bits as an integer that give information about the location * path as a whole. * * @throws javax.xml.transform.TransformerException */ public static int getAxisFromStep( Compiler compiler, int stepOpCodePos) throws javax.xml.transform.TransformerException { int stepType = compiler.getOp(stepOpCodePos); switch (stepType) { case OpCodes.FROM_FOLLOWING : return Axis.FOLLOWING; case OpCodes.FROM_FOLLOWING_SIBLINGS : return Axis.FOLLOWINGSIBLING; case OpCodes.FROM_PRECEDING : return Axis.PRECEDING; case OpCodes.FROM_PRECEDING_SIBLINGS : return Axis.PRECEDINGSIBLING; case OpCodes.FROM_PARENT : return Axis.PARENT; case OpCodes.FROM_NAMESPACE : return Axis.NAMESPACE; case OpCodes.FROM_ANCESTORS : return Axis.ANCESTOR; case OpCodes.FROM_ANCESTORS_OR_SELF : return Axis.ANCESTORORSELF; case OpCodes.FROM_ATTRIBUTES : return Axis.ATTRIBUTE; case OpCodes.FROM_ROOT : return Axis.ROOT; case OpCodes.FROM_CHILDREN : return Axis.CHILD; case OpCodes.FROM_DESCENDANTS_OR_SELF : return Axis.DESCENDANTORSELF; case OpCodes.FROM_DESCENDANTS : return Axis.DESCENDANT; case OpCodes.FROM_SELF : return Axis.SELF; case OpCodes.OP_EXTFUNCTION : case OpCodes.OP_FUNCTION : case OpCodes.OP_GROUP : case OpCodes.OP_VARIABLE : return Axis.FILTEREDLIST; } throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: " //+ stepType); } /** * Get a corresponding BIT_XXX from an axis. * @param axis One of Axis.ANCESTOR, etc. * @return One of BIT_ANCESTOR, etc. */ static public int getAnalysisBitFromAxes(int axis) { switch (axis) // Generate new traverser { case Axis.ANCESTOR : return BIT_ANCESTOR; case Axis.ANCESTORORSELF : return BIT_ANCESTOR_OR_SELF; case Axis.ATTRIBUTE : return BIT_ATTRIBUTE; case Axis.CHILD : return BIT_CHILD; case Axis.DESCENDANT : return BIT_DESCENDANT; case Axis.DESCENDANTORSELF : return BIT_DESCENDANT_OR_SELF; case Axis.FOLLOWING : return BIT_FOLLOWING; case Axis.FOLLOWINGSIBLING : return BIT_FOLLOWING_SIBLING; case Axis.NAMESPACE : case Axis.NAMESPACEDECLS : return BIT_NAMESPACE; case Axis.PARENT : return BIT_PARENT; case Axis.PRECEDING : return BIT_PRECEDING; case Axis.PRECEDINGSIBLING : return BIT_PRECEDING_SIBLING; case Axis.SELF : return BIT_SELF; case Axis.ALLFROMNODE : return BIT_DESCENDANT_OR_SELF; // case Axis.PRECEDINGANDANCESTOR : case Axis.DESCENDANTSFROMROOT : case Axis.ALL : case Axis.DESCENDANTSORSELFFROMROOT : return BIT_ANY_DESCENDANT_FROM_ROOT; case Axis.ROOT : return BIT_ROOT; case Axis.FILTEREDLIST : return BIT_FILTER; default : return BIT_FILTER; } } static boolean functionProximateOrContainsProximate(Compiler compiler, int opPos) { int endFunc = opPos + compiler.getOp(opPos + 1) - 1; opPos = compiler.getFirstChildPos(opPos); int funcID = compiler.getOp(opPos); // System.out.println("funcID: "+funcID); // System.out.println("opPos: "+opPos); // System.out.println("endFunc: "+endFunc); switch(funcID) { case FunctionTable.FUNC_LAST: case FunctionTable.FUNC_POSITION: return true; default: opPos++; int i = 0; for (int p = opPos; p < endFunc; p = compiler.getNextOpPos(p), i++) { int innerExprOpPos = p+2; int argOp = compiler.getOp(innerExprOpPos); boolean prox = isProximateInnerExpr(compiler, innerExprOpPos); if(prox) return true; } } return false; } static boolean isProximateInnerExpr(Compiler compiler, int opPos) { int op = compiler.getOp(opPos); int innerExprOpPos = opPos+2; switch(op) { case OpCodes.OP_ARGUMENT: if(isProximateInnerExpr(compiler, innerExprOpPos)) return true; break; case OpCodes.OP_VARIABLE: case OpCodes.OP_NUMBERLIT: case OpCodes.OP_LITERAL: case OpCodes.OP_LOCATIONPATH: break; // OK case OpCodes.OP_FUNCTION: boolean isProx = functionProximateOrContainsProximate(compiler, opPos); if(isProx) return true; break; case OpCodes.OP_GT: case OpCodes.OP_GTE: case OpCodes.OP_LT: case OpCodes.OP_LTE: case OpCodes.OP_EQUALS: int leftPos = compiler.getFirstChildPos(op); int rightPos = compiler.getNextOpPos(leftPos); isProx = isProximateInnerExpr(compiler, leftPos); if(isProx) return true; isProx = isProximateInnerExpr(compiler, rightPos);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -