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;
  }
  
  
  

Reply via email to