sboag       99/12/12 23:52:10

  Modified:    src/org/apache/xalan/xpath SimpleNodeLocator.java
                        XLocator.java
  Log:
  Added union method to XLocator interface.  Tried depth-first union searches, 
but put it on hold for the time being... code is commented out for right now.
  
  Revision  Changes    Path
  1.4       +601 -180  
xml-xalan/src/org/apache/xalan/xpath/SimpleNodeLocator.java
  
  Index: SimpleNodeLocator.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/src/org/apache/xalan/xpath/SimpleNodeLocator.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- SimpleNodeLocator.java    1999/11/28 10:26:16     1.3
  +++ SimpleNodeLocator.java    1999/12/13 07:52:10     1.4
  @@ -204,8 +204,120 @@
               
       return results;
     }
  +  
  +  /**
  +   * Analyze a union pattern and tell if the axes are 
  +   * all descendants.
  +   */
  +  /*
  +  boolean isLocationPathAllDescendants(XPath xpath, int opPos)
  +  {
  +    int posOfLastOp = xpath.getNextOpPos(opPos)-1;
  +    
  +    opPos = xpath.getFirstChildPos(opPos);
  +    while(opPos < posOfLastOp)
  +    {
  +      // step
  +      int stepType = xpath.m_opMap[opPos];
  +      
  +      switch(stepType)
  +      {
  +      case xpath.FROM_SELF:
  +      case xpath.FROM_ATTRIBUTES: // ?
  +      case xpath.FROM_CHILDREN:
  +      // case xpath.FROM_DESCENDANTS:
  +      // case xpath.FROM_DESCENDANTS_OR_SELF:
  +        // case xpath.FROM_FOLLOWING:  ...might do these later
  +        // case xpath.FROM_FOLLOWING_SIBLINGS: ...might do these later
  +        break;
  +      default:
  +        return false;
  +      }
  +
  +      opPos = xpath.getNextOpPos(opPos);
  +    }
  +    if(xpath.m_opMap[opPos] != xpath.ENDOP)
  +    {
  +      System.out.println("ERROR! Could not find ENDOP after 
OP_LOCATIONPATH");
  +    }
  +    return true;
  +  }
  +  */
  +
  +  
  +  /**
  +   * Analyze a union pattern and tell if the axes are 
  +   * all descendants.
  +   */
  +  /*
  +  boolean isUnionOfDescendants(XPath xpath, int opPos)
  +  {
  +    opPos = xpath.getFirstChildPos(opPos);
  +    while(xpath.m_opMap[opPos] == xpath.OP_LOCATIONPATH)
  +    {
  +      int nextOpPos = xpath.getNextOpPos(opPos);
  +      if(!isLocationPathAllDescendants(xpath, opPos))
  +      {
  +        return false;
  +      }
  +      opPos = nextOpPos;
  +    }
  +    return true;
  +  }
  +  */
   
     /**
  +   * Computes the union of its operands which must be node-sets.
  +   * @param context The current source tree context node.
  +   * @param opPos The current position in the m_opMap array.
  +   * @returns the union of node-set operands, or an empty set if 
  +   * callback methods are used.
  +   */
  +  public XNodeSet union(XPath xpath, XPathSupport execContext, 
  +                           Node context, int opPos) 
  +    throws org.xml.sax.SAXException
  +  {
  +    XNodeSet resultNodeSet = null;
  +    
  +    /*
  +    if(false && isUnionOfDescendants(xpath, opPos))
  +    {
  +      // If this is a union of all descendants, and doesn't 
  +      // contain any indexes, then we can safely do a depth-first 
  +      // walk, analyzing all the union at once, and execute call-backs 
  +      // as soon as we locate the nodes.
  +
  +      UnionContext unionContext = new UnionContext(xpath.m_opMap, opPos);
  +      
  +      MutableNodeList mnl = depthStep(xpath, execContext, context, 
unionContext, 1);
  +    }
  +    else
  +    */
  +    {
  +      opPos = xpath.getFirstChildPos(opPos);
  +
  +      while(xpath.m_opMap[opPos] == xpath.OP_LOCATIONPATH)
  +      {
  +        int nextOpPos = xpath.getNextOpPos(opPos);
  +
  +        XNodeSet expr = (XNodeSet)xpath.execute(execContext, context, opPos);
  +        if(null == resultNodeSet)
  +        {
  +          resultNodeSet = expr;
  +        }
  +        else
  +        {
  +          MutableNodeList nl = resultNodeSet.mutableNodeset();
  +          nl.addNodesInDocOrder(expr.nodeset(), execContext);
  +        }
  +        opPos = nextOpPos;
  +      }
  +    }
  +    
  +    return resultNodeSet;
  +  }
  +
  +  /**
      * Execute a location path.  Normally, this method simply 
      * moves past the OP_LOCATIONPATH and it's length member, 
      * and calls the Step function, which will recursivly process 
  @@ -216,10 +328,11 @@
      * @param opPos The current position in the xpath.m_opMap array.
      * @returns the result of the query in an XNodeSet object.
      */
  -  public XNodeSet locationPath(XPath xpath, XPathSupport execContext, Node 
context, int opPos) 
  +  public XNodeSet locationPath(XPath xpath, XPathSupport execContext, 
  +                               Node context, int opPos) 
       throws org.xml.sax.SAXException
     {    
  -    opPos+=2;
  +    opPos = xpath.getFirstChildPos(opPos);
       XNodeSet results;
       MutableNodeList mnl = step(xpath, execContext, context, opPos);
       if(null != mnl)
  @@ -235,6 +348,310 @@
     }
     
     /**
  +   * For use by the depthStep function.
  +   */
  +  protected boolean testPredicates(XPath xpath, 
  +                                   XPathSupport execContext, 
  +                                   Node context, 
  +                                   UnionContext unionContext,
  +                                   int opPos, int whichLocationPath)
  +    throws org.xml.sax.SAXException
  +  {
  +    boolean doNotFilter = true;
  +    int childPosOfStep = xpath.getFirstChildPosOfStep(opPos);
  +    int argLen = xpath.getArgLengthOfStep(opPos);
  +    childPosOfStep+=argLen;
  +    int nextStepType = xpath.m_opMap[childPosOfStep];
  +    while(xpath.OP_PREDICATE == nextStepType)
  +    {
  +      XObject pred = xpath.predicate(execContext, context, childPosOfStep);
  +      if(XObject.CLASS_NUMBER == pred.getType())
  +      {
  +        if(unionContext.getNodePosition(whichLocationPath) != 
(int)pred.num())
  +        {
  +          doNotFilter = false;
  +        }
  +      }
  +      else if(!pred.bool())
  +      {
  +        doNotFilter = false;
  +      }
  +
  +      childPosOfStep = xpath.getNextOpPos(childPosOfStep);
  +      nextStepType = xpath.m_opMap[childPosOfStep];
  +    }
  +    return doNotFilter;
  +  }
  +  
  +  /**
  +   * Process the current stack of steps for the given 
  +   * context node.
  +   * walkInstructions[0] will contain shouldWalkSubtree?
  +   * walkInstructions[1] will contain shouldWalkAttributes?
  +   * @return if the node should be processed.
  +   */
  +  boolean evalSteps(XPath xpath, XPathSupport execContext, 
  +                       Node context, 
  +                       UnionContext unionContext,
  +                       int nLP,
  +                       boolean hasChildNodes,
  +                       boolean isSelf,
  +                       boolean[] walkInstructions)
  +    throws org.xml.sax.SAXException
  +  {
  +    boolean shouldProcessNode = false;
  +    boolean shouldWalkSubtree = false;  // Tell if we should walk the 
subtree.
  +    boolean shouldWalkAttributes = false;  // Tell if we should walk the 
subtree.
  +   
  +    for(int i = 0; i < nLP; i++)
  +    {
  +      int opPos = unionContext.peek(i);
  +      int stepType;
  +      int argLen = 0;
  +      if(UnionContext.PSUEDO_POS_FOUNDNODE == opPos)
  +      {
  +        stepType = UnionContext.PSUEDO_OP_FOUNDNODE;
  +        argLen = 0;
  +      }
  +      else
  +      {
  +        stepType = xpath.m_opMap[opPos];
  +        int posOfNext = xpath.getNextOpPos(opPos);
  +        int nextStepType = xpath.m_opMap[posOfNext];
  +        
  +        if(!isSelf || (stepType == XPath.FROM_DESCENDANTS_OR_SELF) ||
  +           (stepType == XPath.FROM_SELF))
  +        {
  +          int childPosOfStep = xpath.getFirstChildPosOfStep(opPos);
  +          argLen = xpath.getArgLengthOfStep(opPos);
  +          // System.out.println("Testing: "+context.getNodeName());
  +          int origStepType = stepType;
  +          int posOfNextIfSuccess;
  +          if((stepType == XPath.FROM_DESCENDANTS) || 
  +               (stepType == XPath.FROM_DESCENDANTS_OR_SELF))
  +          {
  +            childPosOfStep = xpath.getFirstChildPosOfStep(posOfNext);
  +            argLen = xpath.getArgLengthOfStep(posOfNext);
  +            posOfNextIfSuccess = xpath.getNextOpPos(posOfNext);
  +            stepType = nextStepType;
  +          }
  +          else
  +          {
  +            posOfNextIfSuccess = posOfNext;
  +          }
  +          if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, 
  +                                                context, childPosOfStep, 
  +                                                argLen, stepType))
  +          {            
  +            // NodeList savedContextNodeList = 
execContext.getContextNodeList();
  +            // execContext.setContextNodeList(queryResults);
  +            boolean doNotFilter = testPredicates(xpath, 
  +                                                 execContext, 
  +                                                 context, 
  +                                                 unionContext,
  +                                                 opPos, i);
  +            
  +            opPos = doNotFilter ? posOfNext : 
UnionContext.PSUEDO_POS_FOUNDNODE;
  +            argLen = 0;
  +            
  +            if(opPos != UnionContext.PSUEDO_POS_FOUNDNODE)
  +            {
  +              if(XPath.ENDOP == nextStepType)
  +              {                
  +                if(!((origStepType == XPath.FROM_DESCENDANTS) || 
  +                     (origStepType == XPath.FROM_DESCENDANTS_OR_SELF)))
  +                {
  +                  stepType = UnionContext.PSUEDO_OP_FOUNDNODE;
  +                }
  +                shouldProcessNode = true;
  +              }
  +              else
  +              {
  +                shouldWalkSubtree = true;
  +                if((false == shouldWalkAttributes) && (nextStepType == 
XPath.FROM_ATTRIBUTES))
  +                {
  +                  shouldWalkAttributes = true;
  +                }
  +              }
  +              unionContext.incrementNodePosition(i);
  +            }
  +          }
  +          if(hasChildNodes)
  +          {
  +            argLen = 0;  // Do not increment to next expression position.
  +            
  +            // If this is a FROM_DESCENDANTS or FROM_DESCENDANTS_OR_SELF, 
then 
  +            // continue to process, otherwise push a PSUEDO_POS_FOUNDNODE so 
  +            // the processing for this expression will stop for the next 
  +            // level in the tree.
  +            if(!((origStepType == XPath.FROM_DESCENDANTS) || 
  +                 (origStepType == XPath.FROM_DESCENDANTS_OR_SELF)))
  +            {
  +              // Even though we didn't find the node, setting it thus 
  +              // will prevent us from continuing to process this 
LocationPath.
  +              opPos = UnionContext.PSUEDO_POS_FOUNDNODE;
  +            }
  +          }
  +        }
  +        else // if not testing the self node
  +        {
  +          shouldWalkSubtree = true; // we'll need to continue to children
  +        }
  +      }
  +      if(hasChildNodes)
  +      {
  +        opPos = opPos += argLen;
  +        unionContext.push(i, opPos, 1);
  +      }
  +    } // end for(int i = 0; i < nLP; i++)
  +    
  +    if(null != walkInstructions)
  +    {
  +      walkInstructions[0] = shouldWalkSubtree;
  +      walkInstructions[1] = shouldWalkAttributes;
  +    }
  +    
  +    return shouldProcessNode;
  +  }
  +    
  +  /**
  +   * Execute a step and predicates in a location path, walking the 
  +   * tree depth first, and executing the callback method (if there 
  +   * is one) as soon as the node is located.  This method should 
  +   * only be called when all steps in the LocationPaths are going 
  +   * to be on the forward axes.
  +   * @param xpath The xpath that is executing.
  +   * @param context The current source tree context node.
  +   * @param opPos The current position in the xpath.m_opMap array.
  +   * @returns a node-set.
  +   * @see org.apache.xalan.xpath.SimpleNodeLocator#step(XPath xpath, 
XPathSupport execContext, Node context, int opPos)
  +   */
  +  protected MutableNodeList depthStep(XPath xpath, 
  +                                      XPathSupport execContext, 
  +                                      Node context, 
  +                                      UnionContext unionContext,
  +                                      int indexPos) 
  +    throws org.xml.sax.SAXException
  +  {    
  +    MutableNodeList queryResults = new MutableNodeListImpl();
  +    
  +    Node top = context;
    NodeCallback callback = execContext.getCallback();
  +    Object callbackInfo = execContext.getCallbackInfo();
  +    execContext.setCallback(null, null);
  +    
  +    // We have to flag if we're at the top of the tree, so we 
  +    // don't try to process the self node for FROM_CHILDREN, etc.
  +    // This is faster than context.equals(top).
  +    boolean isSelf = true;
  +    
  +    // The number of location paths is constant throughout the 
  +    // tree walk.
  +    int nLP = unionContext.getLocationPathCount();
  +    boolean[] walkInstructions = {false, false};
  +
  +    while(null != context)
  +    {     
  +      boolean hasChildNodes = (context.getNodeType() != Node.ATTRIBUTE_NODE) 
?
  +                              context.hasChildNodes() : false;
  +      
  +      boolean shouldProcess = evalSteps(xpath, execContext, 
  +                       context, unionContext, nLP,
  +                       hasChildNodes, isSelf,
  +                       walkInstructions);
  +      boolean shouldWalkSubtree = walkInstructions[0];
  +      boolean shouldWalkAttributes = walkInstructions[1];
  +      
  +      if(shouldProcess)
  +      {
  +        if(null != callback)
  +          callback.processLocatedNode(execContext, context, callbackInfo);
  +        else
  +          queryResults.addNode(context);
  +      }
  +      
  +      // We have to do a special walk for the attributes.
  +      if(shouldWalkAttributes)
  +      {
  +        // If they're no child nodes, he
  +        // to go and push the next steps on the stack, since 
  +        // they were not pushed by evalSteps (the reason is a long story...).
  +        // Only need to push FROM_ATTRIBUTES, the rest can go on as 
  +        // PSUEDO_POS_FOUNDNODE, to avoid extra work.
  +        if(!hasChildNodes)
  +        {
  +          for(int x = 0; x < nLP; x++)
  +          {
  +            int nextOpPos = unionContext.peek(x);
  +            if(UnionContext.PSUEDO_POS_FOUNDNODE != nextOpPos)
  +            {
  +              nextOpPos = xpath.getNextOpPos(nextOpPos);
  +              if(!(XPath.FROM_ATTRIBUTES == xpath.m_opMap[nextOpPos]))
  +                nextOpPos = UnionContext.PSUEDO_POS_FOUNDNODE;
  +            }
  +            unionContext.push(x, nextOpPos, 1);
  +          }
  +        }
  +        NamedNodeMap attrs = context.getAttributes();
  +        int n = attrs.getLength();
  +        for(int k = 0; k < n; k++)
  +        {
  +          shouldProcess = evalSteps(xpath, execContext, 
  +                                    attrs.item(k), unionContext, nLP,
  +                                    false, isSelf, null);
  +          if(shouldProcess)
  +          {
  +            if(null != callback)
  +              callback.processLocatedNode(execContext, attrs.item(k), 
callbackInfo);
  +            else
  +              queryResults.addNode(context);
  +          }
  +        }
  +        if(!hasChildNodes)
  +          unionContext.pop(); // pop what we just pushed, ready for children.
  +      }
  +            
  +      if(isSelf)
  +        isSelf = false;
  +      
  +      // If this node has child nodes, but all patterns are complete 
  +      // or failed, then we don't want to walk the subtree, so we 
  +      // have to pop the stack that was pushed in anticipation of 
  +      // processing the children.
  +      Node nextNode;
  +      if(shouldWalkSubtree && hasChildNodes)
  +      {
  +        nextNode = context.getFirstChild();
  +      }
  +      else 
  +      {
  +        nextNode = null;
  +        if(hasChildNodes)
  +          unionContext.pop(); // pop all the positions.
  +      }
  +      
  +      while(null == nextNode)
  +      {
  +        if(top.equals( context ))
  +          break;
  +        nextNode = context.getNextSibling();
  +        if(null == nextNode)
  +        {
  +          unionContext.pop(); // pop all the positions.
  +          context = context.getParentNode();
  +          if((null == context) || (top.equals( context )))
  +          {
  +            nextNode = null;
  +            break;
  +          }
  +        }
  +      }
  +      context = nextNode;
  +    }
  +
  +    return queryResults;
  +  }
  +  
  +  /**
      * Execute a step and predicates in a location path.  This recursivly 
      * executes each of the steps and predicates.
      * The step can be oneof xpath.OP_VARIABLE, OP_EXTFUNCTION,
  @@ -395,94 +812,6 @@
     }
     
     /**
  -   * Execute a step that performs an OP_VARIABLE, OP_EXTFUNCTION,
  -   * OP_FUNCTION, or OP_GROUP function.
  -   * @param xpath The xpath that is executing.
  -   * @param context The current source tree context node.
  -   * @param opPos The current position in the xpath.m_opMap array.
  -   * @param stepType One of OP_VARIABLE, OP_EXTFUNCTION,
  -   * OP_FUNCTION, or OP_GROUP.
  -   * @param subQueryResults Should be an empty node list where the 
  -   * results of the step will be put.
  -   * @returns the length of the argument (i.e. amount to add to predicate 
pos 
  -   * or end of step).
  -   */
  -  protected int findNodeSet(XPath xpath, XPathSupport execContext, Node 
context, int opPos, 
  -                              int stepType, MutableNodeList subQueryResults)
  -    throws org.xml.sax.SAXException
  -  {
  -        XObject obj = xpath.execute(execContext, context, opPos);
  -        NodeList nl = obj.nodeset();
  -        
  -        // Should this be adding in doc order?
  -        // We can not simply assign the nl value to 
  -        // subQueryResults, because nl may be a ref to 
  -        // a variable or the like, and we may mutate 
  -        // below... which results in a hard-to-find bug!
  -        subQueryResults.addNodes(nl);
  -        return xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH];
  -  }
  -  
  -  /**
  -   * Execute a step to the root.
  -   * @param xpath The xpath that is executing.
  -   * @param context The current source tree context node.
  -   * @param opPos The current position in the xpath.m_opMap array.
  -   * @param stepType Value of xpath.FROM_ROOT.
  -   * @param subQueryResults Should be an empty node list where the 
  -   * results of the step will be put.
  -   * @returns the length of the argument (i.e. amount to add to predicate 
pos 
  -   * or end of step).
  -   */
  -  protected int findRoot(XPath xpath, XPathSupport execContext, Node 
context, int opPos, 
  -                           int stepType, MutableNodeList subQueryResults)
  -    throws org.xml.sax.SAXException
  -  {
  -    int argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -    opPos += 3;
  -
  -    Document docContext = (Node.DOCUMENT_NODE == context.getNodeType()) 
  -                          ? (Document)context : context.getOwnerDocument();
  -    subQueryResults.addNode(docContext);
  -    return argLen+3;
  -  }
  -  
  -  /**
  -   * Add the parent to the list if it meets the NodeTest qualification.
  -   * @param xpath The xpath that is executing.
  -   * @param context The current source tree context node.
  -   * @param opPos The current position in the xpath.m_opMap array.
  -   * @param stepType Value of xpath.FROM_PARENT.
  -   * @param subQueryResults Should be an empty node list where the 
  -   * results of the step will be put.
  -   * @returns the length of the argument (i.e. amount to add to predicate 
pos 
  -   * or end of step).
  -   */
  -  protected int findParent(XPath xpath, XPathSupport execContext, Node 
context, int opPos, 
  -                             int stepType, MutableNodeList subQueryResults)
  -    throws org.xml.sax.SAXException
  -  {
  -    context = execContext.getParentOfNode(context);
  -    int argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -    if(null != context)
  -    {
  -      opPos += 3;
  -      if(argLen > 0)
  -      {
  -        if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, context, 
opPos, argLen, stepType))
  -        {
  -          subQueryResults.addNode(context);
  -        }
  -      }
  -      else
  -      {
  -        subQueryResults.addNode(context);
  -      }
  -    }
  -    return argLen+3;
  -  }
  -  
  -  /**
      * Add the context to the list if it meets the NodeTest qualification.
      * @param xpath The xpath that is executing.
      * @param context The current source tree context node.
  @@ -497,8 +826,8 @@
                                int stepType, MutableNodeList subQueryResults)
       throws org.xml.sax.SAXException
     {
  -    int argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -    opPos += 3;
  +    int argLen = xpath.getArgLengthOfStep(opPos);
  +    opPos = xpath.getFirstChildPosOfStep(opPos);
       if(argLen > 0)
       {
         if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, context, 
opPos, argLen, stepType))
  @@ -512,65 +841,7 @@
       }
       return argLen+3;
     }
  -
  -  /**
  -   * Add ancestors to the list if they meet the NodeTest qualification.
  -   * @param xpath The xpath that is executing.
  -   * @param context The current source tree context node.
  -   * @param opPos The current position in the xpath.m_opMap array.
  -   * @param stepType Value of xpath.FROM_ANCESTORS.
  -   * @param subQueryResults Should be an empty node list where the 
  -   * results of the step will be put.
  -   * @returns the length of the argument (i.e. amount to add to predicate 
pos 
  -   * or end of step).
  -   */
  -  protected int findAncestors(XPath xpath, XPathSupport execContext, Node 
context, int opPos, 
  -                             int stepType, MutableNodeList subQueryResults)
  -    throws org.xml.sax.SAXException
  -  {
  -    context = execContext.getParentOfNode(context);
  -    int argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -    opPos += 3;
  -    while(null != context)
  -    {
  -      if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, context, 
opPos, argLen, stepType))
  -      {
  -        subQueryResults.addNode(context);
  -      }
  -      context = execContext.getParentOfNode(context);
  -    }
  -    return argLen+3;
  -  }
  - 
  -  /**
  -   * Add ancestors or the context to the list if they meet 
  -   * the NodeTest qualification.
  -   * @param xpath The xpath that is executing.
  -   * @param context The current source tree context node.
  -   * @param opPos The current position in the xpath.m_opMap array.
  -   * @param stepType Value of xpath.FROM_ANCESTORS_OR_SELF.
  -   * @param subQueryResults Should be an empty node list where the 
  -   * results of the step will be put.
  -   * @returns the length of the argument (i.e. amount to add to predicate 
pos 
  -   * or end of step).
  -   */
  -  protected int findAncestorsOrSelf(XPath xpath, XPathSupport execContext, 
Node context, int opPos, 
  -                             int stepType, MutableNodeList subQueryResults)
  -    throws org.xml.sax.SAXException
  -  {
  -    int argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -    opPos += 3;
  -    while(null != context)
  -    {
  -      if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, context, 
opPos, argLen, stepType))
  -      {
  -        subQueryResults.addNode(context);
  -      }
  -      context = execContext.getParentOfNode(context);
  -    }
  -    return argLen+3;
  -  }
  -
  +  
     /**
      * Add attributes to the list if they meet 
      * the NodeTest qualification.
  @@ -587,8 +858,8 @@
                                    int stepType, MutableNodeList 
subQueryResults)
       throws org.xml.sax.SAXException
     {
  -    int argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -    opPos += 3;
  +    int argLen = xpath.getArgLengthOfStep(opPos);
  +    opPos = xpath.getFirstChildPosOfStep(opPos);
       if( (null != context) && (context.getNodeType()==Node.ELEMENT_NODE) )
       {
         NamedNodeMap attributeList = context.getAttributes();
  @@ -624,8 +895,8 @@
                                  int stepType, MutableNodeList subQueryResults)
       throws org.xml.sax.SAXException
     {
  -    int argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -    opPos += 3;
  +    int argLen = xpath.getArgLengthOfStep(opPos);
  +    opPos = xpath.getFirstChildPosOfStep(opPos);
       // If using a document fragment with references (non-standard) 
       // we can not use the next-sibling business at the top level.
       if(Node.DOCUMENT_FRAGMENT_NODE != context.getNodeType())
  @@ -635,6 +906,8 @@
         {
           if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, c, opPos, 
argLen, stepType))
           {
  +          // or else call execute method.  If no execute method,
  +          // add the node.
             subQueryResults.addNode(c);
           }
           c = c.getNextSibling();
  @@ -674,8 +947,8 @@
                                   int stepType, MutableNodeList 
subQueryResults)
       throws org.xml.sax.SAXException
     {
  -    int argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -    opPos += 3;
  +    int argLen = xpath.getArgLengthOfStep(opPos);
  +    opPos = xpath.getFirstChildPosOfStep(opPos);
   
       // Perform a pre-order traversal of descendents.
       // Note that I would like to be able to do optimization here 
  @@ -787,8 +1060,8 @@
                                   int stepType, MutableNodeList 
subQueryResults)
       throws org.xml.sax.SAXException
     {
  -    int argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -    opPos += 3;
  +    int argLen = xpath.getArgLengthOfStep(opPos);
  +    opPos = xpath.getFirstChildPosOfStep(opPos);
   
       // What fun...
       Document doc = context.getOwnerDocument();
  @@ -844,8 +1117,8 @@
                                         int stepType, MutableNodeList 
subQueryResults)
       throws org.xml.sax.SAXException
     {
  -    int argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -    opPos += 3;
  +    int argLen = xpath.getArgLengthOfStep(opPos);
  +    opPos = xpath.getFirstChildPosOfStep(opPos);
   
       Node pos = context.getNextSibling();
       while(null != pos)
  @@ -859,6 +1132,153 @@
       return argLen+3;
     }
     
  +  
  +  /**
  +   * Execute a step that performs an OP_VARIABLE, OP_EXTFUNCTION,
  +   * OP_FUNCTION, or OP_GROUP function.
  +   * @param xpath The xpath that is executing.
  +   * @param context The current source tree context node.
  +   * @param opPos The current position in the xpath.m_opMap array.
  +   * @param stepType One of OP_VARIABLE, OP_EXTFUNCTION,
  +   * OP_FUNCTION, or OP_GROUP.
  +   * @param subQueryResults Should be an empty node list where the 
  +   * results of the step will be put.
  +   * @returns the length of the argument (i.e. amount to add to predicate 
pos 
  +   * or end of step).
  +   */
  +  protected int findNodeSet(XPath xpath, XPathSupport execContext, Node 
context, int opPos, 
  +                              int stepType, MutableNodeList subQueryResults)
  +    throws org.xml.sax.SAXException
  +  {
  +        XObject obj = xpath.execute(execContext, context, opPos);
  +        NodeList nl = obj.nodeset();
  +        
  +        // Should this be adding in doc order?
  +        // We can not simply assign the nl value to 
  +        // subQueryResults, because nl may be a ref to 
  +        // a variable or the like, and we may mutate 
  +        // below... which results in a hard-to-find bug!
  +        subQueryResults.addNodes(nl);
  +        return xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH];
  +  }
  +  
  +  /**
  +   * Execute a step to the root.
  +   * @param xpath The xpath that is executing.
  +   * @param context The current source tree context node.
  +   * @param opPos The current position in the xpath.m_opMap array.
  +   * @param stepType Value of xpath.FROM_ROOT.
  +   * @param subQueryResults Should be an empty node list where the 
  +   * results of the step will be put.
  +   * @returns the length of the argument (i.e. amount to add to predicate 
pos 
  +   * or end of step).
  +   */
  +  protected int findRoot(XPath xpath, XPathSupport execContext, Node 
context, int opPos, 
  +                           int stepType, MutableNodeList subQueryResults)
  +    throws org.xml.sax.SAXException
  +  {
  +    int argLen = xpath.getArgLengthOfStep(opPos);
  +    opPos = xpath.getFirstChildPosOfStep(opPos);
  +
  +    Document docContext = (Node.DOCUMENT_NODE == context.getNodeType()) 
  +                          ? (Document)context : context.getOwnerDocument();
  +    subQueryResults.addNode(docContext);
  +    return argLen+3;
  +  }
  +  
  +  /**
  +   * Add the parent to the list if it meets the NodeTest qualification.
  +   * @param xpath The xpath that is executing.
  +   * @param context The current source tree context node.
  +   * @param opPos The current position in the xpath.m_opMap array.
  +   * @param stepType Value of xpath.FROM_PARENT.
  +   * @param subQueryResults Should be an empty node list where the 
  +   * results of the step will be put.
  +   * @returns the length of the argument (i.e. amount to add to predicate 
pos 
  +   * or end of step).
  +   */
  +  protected int findParent(XPath xpath, XPathSupport execContext, Node 
context, int opPos, 
  +                             int stepType, MutableNodeList subQueryResults)
  +    throws org.xml.sax.SAXException
  +  {
  +    context = execContext.getParentOfNode(context);
  +    int argLen = xpath.getArgLengthOfStep(opPos);
  +    if(null != context)
  +    {
  +      opPos = xpath.getFirstChildPosOfStep(opPos);
  +      if(argLen > 0)
  +      {
  +        if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, context, 
opPos, argLen, stepType))
  +        {
  +          subQueryResults.addNode(context);
  +        }
  +      }
  +      else
  +      {
  +        subQueryResults.addNode(context);
  +      }
  +    }
  +    return argLen+3;
  +  }
  +  
  +  /**
  +   * Add ancestors to the list if they meet the NodeTest qualification.
  +   * @param xpath The xpath that is executing.
  +   * @param context The current source tree context node.
  +   * @param opPos The current position in the xpath.m_opMap array.
  +   * @param stepType Value of xpath.FROM_ANCESTORS.
  +   * @param subQueryResults Should be an empty node list where the 
  +   * results of the step will be put.
  +   * @returns the length of the argument (i.e. amount to add to predicate 
pos 
  +   * or end of step).
  +   */
  +  protected int findAncestors(XPath xpath, XPathSupport execContext, Node 
context, int opPos, 
  +                             int stepType, MutableNodeList subQueryResults)
  +    throws org.xml.sax.SAXException
  +  {
  +    context = execContext.getParentOfNode(context);
  +    int argLen = xpath.getArgLengthOfStep(opPos);
  +    opPos = xpath.getFirstChildPosOfStep(opPos);
  +    while(null != context)
  +    {
  +      if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, context, 
opPos, argLen, stepType))
  +      {
  +        subQueryResults.addNode(context);
  +      }
  +      context = execContext.getParentOfNode(context);
  +    }
  +    return argLen+3;
  +  }
  + 
  +  /**
  +   * Add ancestors or the context to the list if they meet 
  +   * the NodeTest qualification.
  +   * @param xpath The xpath that is executing.
  +   * @param context The current source tree context node.
  +   * @param opPos The current position in the xpath.m_opMap array.
  +   * @param stepType Value of xpath.FROM_ANCESTORS_OR_SELF.
  +   * @param subQueryResults Should be an empty node list where the 
  +   * results of the step will be put.
  +   * @returns the length of the argument (i.e. amount to add to predicate 
pos 
  +   * or end of step).
  +   */
  +  protected int findAncestorsOrSelf(XPath xpath, XPathSupport execContext, 
Node context, int opPos, 
  +                             int stepType, MutableNodeList subQueryResults)
  +    throws org.xml.sax.SAXException
  +  {
  +    int argLen = xpath.getArgLengthOfStep(opPos);
  +    opPos = xpath.getFirstChildPosOfStep(opPos);
  +    while(null != context)
  +    {
  +      if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, context, 
opPos, argLen, stepType))
  +      {
  +        subQueryResults.addNode(context);
  +      }
  +      context = execContext.getParentOfNode(context);
  +    }
  +    return argLen+3;
  +  }
  +
     /**
      * Add the nodes preceding the context to the list if they meet 
      * the NodeTest qualification.
  @@ -883,8 +1303,8 @@
                                   int stepType, MutableNodeList 
subQueryResults)
       throws org.xml.sax.SAXException
     {
  -    int argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -    opPos += 3;
  +    int argLen = xpath.getArgLengthOfStep(opPos);
  +    opPos = xpath.getFirstChildPosOfStep(opPos);
   
       // Ugh.  Reverse document order, no parents, I guess.
       Document doc = context.getOwnerDocument();
  @@ -952,8 +1372,8 @@
                                         int stepType, MutableNodeList 
subQueryResults)
       throws org.xml.sax.SAXException
     {
  -    int argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -    opPos += 3;
  +    int argLen = xpath.getArgLengthOfStep(opPos);
  +    opPos = xpath.getFirstChildPosOfStep(opPos);
   
       Node pos = context.getPreviousSibling();
       while(null != pos)
  @@ -982,8 +1402,8 @@
                                 int stepType, MutableNodeList subQueryResults)
       throws org.xml.sax.SAXException
     {
  -    int argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -    opPos += 3;
  +    int argLen = xpath.getArgLengthOfStep(opPos);
  +    opPos = xpath.getFirstChildPosOfStep(opPos);
       xpath.error(context, XPATHErrorResources.ERROR0014); //"namespace axis 
not implemented yet!");
       return argLen+3;
     }
  @@ -1003,8 +1423,8 @@
                                 int stepType, MutableNodeList subQueryResults)
       throws org.xml.sax.SAXException
     {
  -    int argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -    opPos += 3;
  +    int argLen = xpath.getArgLengthOfStep(opPos);
  +    opPos = xpath.getFirstChildPosOfStep(opPos);
        xpath.error(context, XPATHErrorResources.ERROR0015, new Object[] 
{Integer.toString(stepType)}); //"unknown axis: "+stepType);
       return argLen+3;
     }
  @@ -1080,7 +1500,7 @@
     public double locationPathPattern(XPath xpath, XPathSupport execContext, 
Node context, int opPos) 
       throws org.xml.sax.SAXException
     {    
  -    opPos+=2;
  +    opPos = xpath.getFirstChildPos(opPos);
       double[] scoreHolder = {xpath.MATCH_SCORE_NONE};
       stepPattern(xpath, execContext, context, opPos, scoreHolder);
       return scoreHolder[0];
  @@ -1142,8 +1562,8 @@
         break;
       case xpath.FROM_ROOT:
         {
  -        argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -        opPos += 3;
  +        argLen = xpath.getArgLengthOfStep(opPos);
  +        opPos = xpath.getFirstChildPosOfStep(opPos);
           Document docContext = (Node.DOCUMENT_NODE == context.getNodeType()) 
                                 ? (Document)context : 
context.getOwnerDocument();
           score = (docContext == context) ? xpath.MATCH_SCORE_OTHER : 
xpath.MATCH_SCORE_NONE;
  @@ -1155,15 +1575,15 @@
         break;
       case xpath.MATCH_ATTRIBUTE:
         {
  -        argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -        opPos += 3;
  +        argLen = xpath.getArgLengthOfStep(opPos);
  +        opPos = xpath.getFirstChildPosOfStep(opPos);
           score = nodeTest(xpath, execContext, context, opPos, argLen, 
xpath.FROM_ATTRIBUTES);
           break;
         }
       case xpath.MATCH_ANY_ANCESTOR:
         {
  -        argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -        opPos += 3;
  +        argLen = xpath.getArgLengthOfStep(opPos);
  +        opPos = xpath.getFirstChildPosOfStep(opPos);
           score = xpath.MATCH_SCORE_NONE;
           while(null != context)
           {
  @@ -1175,13 +1595,13 @@
         }
         break;
       case xpath.MATCH_IMMEDIATE_ANCESTOR:
  -      argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -      opPos += 3;
  +      argLen = xpath.getArgLengthOfStep(opPos);
  +      opPos = xpath.getFirstChildPosOfStep(opPos);
         score = nodeTest(xpath, execContext, context, opPos, argLen, stepType);
         break;
       default:
  -      argLen = xpath.m_opMap[opPos+xpath.MAPINDEX_LENGTH+1]-3;
  -      opPos += 3;
  +      argLen = xpath.getArgLengthOfStep(opPos);
  +      opPos = xpath.getFirstChildPosOfStep(opPos);
         score = xpath.MATCH_SCORE_NONE;
         xpath.error(context, XPATHErrorResources.ERROR0016); //"unknown match 
operation!");
         break;
  @@ -1197,6 +1617,7 @@
         // if I could sense this condition earlier...
         try
         {
  +        // BUG: m_throwFoundIndex is not threadsafe
           xpath.m_throwFoundIndex = true;
           int startPredicates = opPos;
           opPos = startPredicates;
  
  
  
  1.4       +11 -0     xml-xalan/src/org/apache/xalan/xpath/XLocator.java
  
  Index: XLocator.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xpath/XLocator.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- XLocator.java     1999/11/28 10:26:16     1.3
  +++ XLocator.java     1999/12/13 07:52:10     1.4
  @@ -89,6 +89,17 @@
       throws org.xml.sax.SAXException;
     
     /**
  +   * Execute a union. The union of its operands, which are locationPaths,
  +   * must be node-sets.
  +   * @param xpath The xpath that is executing.
  +   * @param context The current source tree context node.
  +   * @param opPos The current position in the xpath.m_opMap array.
  +   * @returns the result of the query in an XNodeSet object.
  +   */
  +  XNodeSet union(XPath xpath, XPathSupport execContext, Node context, int 
opPos) 
  +    throws org.xml.sax.SAXException;
  +
  +  /**
      * Execute a location path.  Normally, this method simply 
      * moves past the OP_LOCATIONPATH and it's length member, 
      * and calls the Step function, which will recursivly process 
  
  
  

Reply via email to