📄 walkerfactory.java
字号:
if(isProx) return true; break; default: return true; // be conservative... } return false; } /** * Tell if the predicates need to have proximity knowledge. */ public static boolean mightBeProximate(Compiler compiler, int opPos, int stepType) throws javax.xml.transform.TransformerException { boolean mightBeProximate = false; int argLen; switch (stepType) { case OpCodes.OP_VARIABLE : case OpCodes.OP_EXTFUNCTION : case OpCodes.OP_FUNCTION : case OpCodes.OP_GROUP : argLen = compiler.getArgLength(opPos); break; default : argLen = compiler.getArgLengthOfStep(opPos); } int predPos = compiler.getFirstPredicateOpPos(opPos); int count = 0; while (OpCodes.OP_PREDICATE == compiler.getOp(predPos)) { count++; int innerExprOpPos = predPos+2; int predOp = compiler.getOp(innerExprOpPos); switch(predOp) { case OpCodes.OP_VARIABLE: return true; // Would need more smarts to tell if this could be a number or not! case OpCodes.OP_LOCATIONPATH: // OK. break; case OpCodes.OP_NUMBER: case OpCodes.OP_NUMBERLIT: return true; // that's all she wrote! case OpCodes.OP_FUNCTION: boolean isProx = functionProximateOrContainsProximate(compiler, innerExprOpPos); if(isProx) return true; break; case OpCodes.OP_GT: case OpCodes.OP_GTE: case OpCodes.OP_LT: case OpCodes.OP_LTE: case OpCodes.OP_EQUALS: int leftPos = compiler.getFirstChildPos(innerExprOpPos); int rightPos = compiler.getNextOpPos(leftPos); isProx = isProximateInnerExpr(compiler, leftPos); if(isProx) return true; isProx = isProximateInnerExpr(compiler, rightPos); if(isProx) return true; break; default: return true; // be conservative... } predPos = compiler.getNextOpPos(predPos); } return mightBeProximate; } /** * Special purpose function to see if we can optimize the pattern for * a DescendantIterator. * * @param compiler non-null reference to compiler object that has processed * the XPath operations into an opcode map. * @param stepOpCodePos The opcode position for the step. * @param stepIndex The top-level step index withing the iterator. * * @return 32 bits as an integer that give information about the location * path as a whole. * * @throws javax.xml.transform.TransformerException */ private static boolean isOptimizableForDescendantIterator( Compiler compiler, int stepOpCodePos, int stepIndex) throws javax.xml.transform.TransformerException { int stepType; int stepCount = 0; boolean foundDorDS = false; boolean foundSelf = false; boolean foundDS = false; int nodeTestType = OpCodes.NODETYPE_NODE; while (OpCodes.ENDOP != (stepType = compiler.getOp(stepOpCodePos))) { // The DescendantIterator can only do one node test. If there's more // than one, use another iterator. if(nodeTestType != OpCodes.NODETYPE_NODE && nodeTestType != OpCodes.NODETYPE_ROOT) return false; stepCount++; if(stepCount > 3) return false; boolean mightBeProximate = mightBeProximate(compiler, stepOpCodePos, stepType); if(mightBeProximate) return false; switch (stepType) { case OpCodes.FROM_FOLLOWING : case OpCodes.FROM_FOLLOWING_SIBLINGS : case OpCodes.FROM_PRECEDING : case OpCodes.FROM_PRECEDING_SIBLINGS : case OpCodes.FROM_PARENT : case OpCodes.OP_VARIABLE : case OpCodes.OP_EXTFUNCTION : case OpCodes.OP_FUNCTION : case OpCodes.OP_GROUP : case OpCodes.FROM_NAMESPACE : case OpCodes.FROM_ANCESTORS : case OpCodes.FROM_ANCESTORS_OR_SELF : case OpCodes.FROM_ATTRIBUTES : case OpCodes.MATCH_ATTRIBUTE : case OpCodes.MATCH_ANY_ANCESTOR : case OpCodes.MATCH_IMMEDIATE_ANCESTOR : return false; case OpCodes.FROM_ROOT : if(1 != stepCount) return false; break; case OpCodes.FROM_CHILDREN : if(!foundDS && !(foundDorDS && foundSelf)) return false; break; case OpCodes.FROM_DESCENDANTS_OR_SELF : foundDS = true; case OpCodes.FROM_DESCENDANTS : if(3 == stepCount) return false; foundDorDS = true; break; case OpCodes.FROM_SELF : if(1 != stepCount) return false; foundSelf = true; break; default : throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: " // + stepType); } nodeTestType = compiler.getStepTestType(stepOpCodePos); int nextStepOpCodePos = compiler.getNextStepPos(stepOpCodePos); if (nextStepOpCodePos < 0) break; if(OpCodes.ENDOP != compiler.getOp(nextStepOpCodePos)) { if(compiler.countPredicates(stepOpCodePos) > 0) { return false; } } stepOpCodePos = nextStepOpCodePos; } return true; } /** * Analyze the location path and return 32 bits that give information about * the location path as a whole. See the BIT_XXX constants for meaning about * each of the bits. * * @param compiler non-null reference to compiler object that has processed * the XPath operations into an opcode map. * @param stepOpCodePos The opcode position for the step. * @param stepIndex The top-level step index withing the iterator. * * @return 32 bits as an integer that give information about the location * path as a whole. * * @throws javax.xml.transform.TransformerException */ private static int analyze( Compiler compiler, int stepOpCodePos, int stepIndex) throws javax.xml.transform.TransformerException { int stepType; int stepCount = 0; int analysisResult = 0x00000000; // 32 bits of analysis while (OpCodes.ENDOP != (stepType = compiler.getOp(stepOpCodePos))) { stepCount++; // String namespace = compiler.getStepNS(stepOpCodePos); // boolean isNSWild = (null != namespace) // ? namespace.equals(NodeTest.WILD) : false; // String localname = compiler.getStepLocalName(stepOpCodePos); // boolean isWild = (null != localname) ? localname.equals(NodeTest.WILD) : false; boolean predAnalysis = analyzePredicate(compiler, stepOpCodePos, stepType); if (predAnalysis) analysisResult |= BIT_PREDICATE; switch (stepType) { case OpCodes.OP_VARIABLE : case OpCodes.OP_EXTFUNCTION : case OpCodes.OP_FUNCTION : case OpCodes.OP_GROUP : analysisResult |= BIT_FILTER; break; case OpCodes.FROM_ROOT : analysisResult |= BIT_ROOT; break; case OpCodes.FROM_ANCESTORS : analysisResult |= BIT_ANCESTOR; break; case OpCodes.FROM_ANCESTORS_OR_SELF : analysisResult |= BIT_ANCESTOR_OR_SELF; break; case OpCodes.FROM_ATTRIBUTES : analysisResult |= BIT_ATTRIBUTE; break; case OpCodes.FROM_NAMESPACE : analysisResult |= BIT_NAMESPACE; break; case OpCodes.FROM_CHILDREN : analysisResult |= BIT_CHILD; break; case OpCodes.FROM_DESCENDANTS : analysisResult |= BIT_DESCENDANT; break; case OpCodes.FROM_DESCENDANTS_OR_SELF : // Use a special bit to to make sure we get the right analysis of "//foo". if (2 == stepCount && BIT_ROOT == analysisResult) { analysisResult |= BIT_ANY_DESCENDANT_FROM_ROOT; } analysisResult |= BIT_DESCENDANT_OR_SELF; break; case OpCodes.FROM_FOLLOWING : analysisResult |= BIT_FOLLOWING; break; case OpCodes.FROM_FOLLOWING_SIBLINGS : analysisResult |= BIT_FOLLOWING_SIBLING; break; case OpCodes.FROM_PRECEDING : analysisResult |= BIT_PRECEDING; break; case OpCodes.FROM_PRECEDING_SIBLINGS : analysisResult |= BIT_PRECEDING_SIBLING; break; case OpCodes.FROM_PARENT : analysisResult |= BIT_PARENT; break; case OpCodes.FROM_SELF : analysisResult |= BIT_SELF; break; case OpCodes.MATCH_ATTRIBUTE : analysisResult |= (BIT_MATCH_PATTERN | BIT_ATTRIBUTE); break; case OpCodes.MATCH_ANY_ANCESTOR : analysisResult |= (BIT_MATCH_PATTERN | BIT_ANCESTOR); break; case OpCodes.MATCH_IMMEDIATE_ANCESTOR : analysisResult |= (BIT_MATCH_PATTERN | BIT_PARENT); break; default : throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: " //+ stepType); } if (OpCodes.NODETYPE_NODE == compiler.getOp(stepOpCodePos + 3)) // child::node() { analysisResult |= BIT_NODETEST_ANY; } stepOpCodePos = compiler.getNextStepPos(stepOpCodePos); if (stepOpCodePos < 0) break; } analysisResult |= (stepCount & BITS_COUNT); return analysisResult; } /** * Tell if the given axis goes downword. Bogus name, if you can think of * a better one, please do tell. This really has to do with inverting * attribute axis. * @param axis One of Axis.XXX. * @return true if the axis is not a child axis and does not go up from * the axis root. */ public static boolean isDownwardAxisOfMany(int axis) { return ((Axis.DESCENDANTORSELF == axis) || (Axis.DESCENDANT == axis) || (Axis.FOLLOWING == axis) // || (Axis.FOLLOWINGSIBLING == axis) || (Axis.PRECEDING == axis) // || (Axis.PRECEDINGSIBLING == axis) ); } /** * Read a <a href="http://www.w3.org/TR/xpath#location-paths">LocationPath</a> * as a generalized match pattern. What this means is that the LocationPath * is read backwards, as a test on a given node, to see if it matches the * criteria of the selection, and ends up at the context node. Essentially, * this is a backwards query from a given node, to find the context node. * <p>So, the selection "foo/daz[2]" is, in non-abreviated expanded syntax, * "self::node()/following-sibling::foo/child::daz[position()=2]". * Taking this as a match pattern for a probable node, it works out to * "self::daz/parent::foo[child::daz[position()=2 and isPrevStepNode()] * precedingSibling::node()[isContextNodeOfLocationPath()]", adding magic * isPrevStepNode and isContextNodeOfLocationPath operations. Predicates in * the location path have to be executed by the following step, * because they have to know the context of their execution. * * @param mpi The MatchPatternIterator to which the steps will be attached. * @param compiler The compiler that holds the syntax tree/op map to * construct from. * @param stepOpCodePos The current op code position within the opmap. * @param stepIndex The top-level step index withing the iterator. * * @return A StepPattern object, which may contain relative StepPatterns. * * @throws javax.xml.transform.TransformerException */ static StepPattern loadSteps( MatchPatternIterator mpi, Compiler compiler, int stepOpCodePos, int stepIndex) throws javax.xml.transform.TransformerException { if (DEBUG_PATTERN_CREATION) { System.out.println("================"); System.out.println("loadSteps for: "+compiler.getPatternString()); } int stepType; StepPattern step = null; StepPattern firstStep = null, prevStep = null; int analysis = analyze(compiler, stepOpCodePos, stepIndex); while (OpCodes.ENDOP != (stepType = compiler.getOp(stepOpCodePos))) { step = createDefaultStepPattern(compiler, stepOpCodePos, mpi, analysis, firstStep, prevStep); if (null == firstStep) { firstStep = step; } else { //prevStep.setNextWalker(step); step.setRelativePathPattern(prevStep); } prevStep = step; stepOpCodePos = compiler.getNextStepPos(stepOpCodePos); if (stepOpCodePos < 0) break; } int axis = Axis.SELF; int paxis = Axis.SELF; StepPattern tail = step; for (StepPattern pat = step; null != pat; pat = pat.getRelativePathPattern()) { int nextAxis = pat.getAxis(); //int nextPaxis = pat.getPredicateAxis(); pat.setAxis(axis); // The predicate axis can't be moved!!! Test Axes103 // pat.setPredicateAxis(paxis); // If we have an attribute or namespace axis that went up, then // it won't find the attribute in the inverse, since the select-to-match // axes are not invertable (an element is a parent of an attribute, but // and attribute is not a child of an element). // If we don't do the magic below, then "@*/ancestor-or-self::*" gets // inverted for match to "self::*/descendant-or-self::@*/parent::node()", // which obviously won't work. // So we will rewrite this as: // "self::*/descendant-or-self::*/attribute::*/parent::node()" // Child has to be rewritten a little differently: // select: "@*/parent::*" // inverted match: "self::*/child::@*/parent::node()" // rewrite: "self::*/attribute::*/parent::node()" // Axes that go down in the select, do not have to have special treatment // in the rewrite. The following inverted match will still not select // anything. // select: "@*/child::*" // inverted match: "self::*/parent::@*/parent::node()" // Lovely business, this. // -sb int whatToShow = pat.getWhatToShow(); if(whatToShow == DTMFilter.SHOW_ATTRIBUTE || whatToShow == DTMFilter.SHOW_NAMESPACE) { int newAxis = (whatToShow == DTMFilter.SHOW_ATTRIBUTE) ? Axis.ATTRIBUTE : Axis.NAMESPACE; if(isDownwardAxisOfMany(axis)) { StepPattern attrPat = new StepPattern(whatToShow, pat.getNamespace(), pat.getLocalName(), //newAxis, pat.getPredicateAxis); newAxis, 0); // don't care about the predicate axis XNumber score = pat.getStaticScore(); pat.setNamespace(null); pat.setLocalName(NodeTest.WILD); attrPat.setPredicates(pat.getPredicates()); pat.setPredicates(null); pat.setWhatToShow(DTMFilter.SHOW_ELEMENT); StepPattern rel = pat.getRelativePathPattern(); pat.setRelativePathPattern(attrPat); attrPat.setRelativePathPattern(rel); attrPat.setStaticScore(score); // This is needed to inverse a following pattern, because of the // wacky Xalan rules for following from an attribute. See axes108. // By these rules, following from an attribute is not strictly // inverseable.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -