You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by sb...@locus.apache.org on 2000/02/13 17:42:46 UTC

cvs commit: xml-xalan/src/org/apache/xalan/xslt AVTPartXPath.java Counter.java CountersTable.java ElemCallTemplate.java ElemExtensionCall.java ElemTemplateElement.java ElemValueOf.java Stylesheet.java StylesheetHandler.java XSLTEngineImpl.java

sboag       00/02/13 08:42:46

  Modified:    src      makexpath4j
               src/org/apache/xalan/xpath ExtensionFunctionHandler.java
                        FuncLast.java SimpleNodeLocator.java
                        UnionContext.java XLocator.java XPath.java
                        XPathProcessorImpl.java XPathSupport.java
                        XPathSupportDefault.java
               src/org/apache/xalan/xpath/xml IntStack.java IntVector.java
                        NodeVector.java XMLParserLiaisonDefault.java
               src/org/apache/xalan/xslt AVTPartXPath.java Counter.java
                        CountersTable.java ElemCallTemplate.java
                        ElemExtensionCall.java ElemTemplateElement.java
                        ElemValueOf.java Stylesheet.java
                        StylesheetHandler.java XSLTEngineImpl.java
  Added:       src/org/apache/xalan/xpath EmptyNodeListImpl.java
  Log:
  Implemented depth-first search for non-union single-step select patterns.  This increases latency, esp. when used with the DTM.
  
  Revision  Changes    Path
  1.13      +1 -0      xml-xalan/src/makexpath4j
  
  Index: makexpath4j
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/makexpath4j,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- makexpath4j	2000/01/31 08:34:46	1.12
  +++ makexpath4j	2000/02/13 16:42:40	1.13
  @@ -70,6 +70,7 @@
       $(XPATHDIR)$(PATHSEP)KeyDeclaration.java \
       $(XPATHDIR)$(PATHSEP)MutableNodeList.java \
       $(XPATHDIR)$(PATHSEP)MutableNodeListImpl.java \
  +    $(XPATHDIR)$(PATHSEP)EmptyNodeListImpl.java \
       $(XPATHDIR)$(PATHSEP)NodeListImpl.java \
       $(XPATHDIR)$(PATHSEP)Process.java \
       $(XPATHDIR)$(PATHSEP)SimpleNodeLocator.java \
  
  
  
  1.7       +8 -6      xml-xalan/src/org/apache/xalan/xpath/ExtensionFunctionHandler.java
  
  Index: ExtensionFunctionHandler.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xpath/ExtensionFunctionHandler.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- ExtensionFunctionHandler.java	1999/12/14 00:21:52	1.6
  +++ ExtensionFunctionHandler.java	2000/02/13 16:42:41	1.7
  @@ -71,13 +71,13 @@
    */
   public class ExtensionFunctionHandler 
   {
  -  protected String namespaceUri;  // uri of the extension namespace
  -  protected String scriptLang = "javaclass";    // scripting language of implementation
  -  protected String scriptSrc;     // script source to run (if any)
  -  protected String scriptSrcURL;  // URL of source of script (if any)
  -  protected Object javaObject = null;    // object for javaclass engine
  +  public String namespaceUri;  // uri of the extension namespace
  +  public String scriptLang = "javaclass";    // scripting language of implementation
  +  public String scriptSrc;     // script source to run (if any)
  +  public String scriptSrcURL;  // URL of source of script (if any)
  +  public Object javaObject = null;    // object for javaclass engine
     protected boolean hasCalledCTor = false;  // we'll be nice and call a ctor if they haven't
  -  protected Class classObject = null;  // class object for javaclass engine
  +  public Class classObject = null;  // class object for javaclass engine
     protected Hashtable functions = new Hashtable (); // functions of namespace
     protected com.ibm.bsf.BSFManager mgr = null; // mgr used to run scripts
     protected boolean componentStarted; // true when the scripts in a
  @@ -239,7 +239,9 @@
             if(!hasCalledCTor)
             {
               if(null == javaObject)
  +            {
                 javaObject = this.classObject.newInstance();
  +            }
               
               argArray = new Object[args.size () + 1];
               argArray[0] = javaObject;
  
  
  
  1.3       +2 -1      xml-xalan/src/org/apache/xalan/xpath/FuncLast.java
  
  Index: FuncLast.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xpath/FuncLast.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- FuncLast.java	1999/11/28 10:26:15	1.2
  +++ FuncLast.java	2000/02/13 16:42:41	1.3
  @@ -74,7 +74,8 @@
      * @return A valid XObject.
      */
     public XObject execute(XPath path, XPathSupport execContext, Node context, int opPos, Vector args) 
  +    throws org.xml.sax.SAXException
     {    
  -    return new XNumber((double)path.getCountOfContextNodeList(execContext));
  +    return new XNumber((double)path.getCountOfContextNodeList(path, execContext,  context));
     }
   }
  
  
  
  1.12      +511 -612  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.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- SimpleNodeLocator.java	2000/02/08 14:43:51	1.11
  +++ SimpleNodeLocator.java	2000/02/13 16:42:41	1.12
  @@ -71,6 +71,11 @@
   public class SimpleNodeLocator implements XLocator, Serializable
   {  
     /**
  +   * Dev-time/QE switch to use optimized, depth-first search, or not.
  +   */
  +  public static boolean USEDEPTHFIRST = true;
  +  
  +  /**
      * Create a SimpleNodeLocator object.
      */
     public SimpleNodeLocator()
  @@ -83,6 +88,16 @@
     private static SimpleNodeLocator m_locater = null;
     
     /**
  +   * Empty node list for failed results.
  +   */
  +  private static MutableNodeList emptyQueryResults = new EmptyNodeListImpl();
  +  
  +  /**
  +   * Empty node list for failed results.
  +   */
  +  private static XNodeSet emptyNodeList = new XNodeSet(emptyQueryResults);
  +
  +  /**
      * The the default locator.
      */
     public static XLocator getDefaultLocator()
  @@ -108,7 +123,7 @@
       m_locater = (null == m_locater) ? new SimpleNodeLocator() : m_locater;
       return m_locater;
     }
  - 
  +  
     /**
      * (Same as query for the moment).
      * @param opPos The current position in the xpath.m_opMap array.
  @@ -120,7 +135,7 @@
       m_locater = (null == m_locater) ? new SimpleNodeLocator() : m_locater;
       return m_locater;
     }
  - 
  +  
     /**
      * Execute a connection (if it was not executed by the static 
      * connect method) and process the following LocationPath, 
  @@ -137,7 +152,7 @@
      * @returns the result of the query in an XNodeSet object.
      */
     public XNodeSet connectToNodes(XPath xpath, XPathSupport execContext, Node context, 
  -                               int opPos, Vector connectArgs) 
  +                                 int opPos, Vector connectArgs) 
       throws org.xml.sax.SAXException
     {    
       String fileSpec = ((XObject)connectArgs.elementAt(0)).str();
  @@ -170,9 +185,10 @@
               Document doc = execContext.parseXML(url, null, null);
               if(null != doc)
               {
  -              if((xpath.OP_LOCATIONPATH == xpath.m_opMap[opPos]))
  +              int op = xpath.m_opMap[opPos];
  +              if(xpath.OP_LOCATIONPATH == (op & XPath.LOCATIONPATHEX_MASK))
                 {
  -                XNodeSet xnl = xpath.locationPath(execContext, doc, opPos);
  +                XNodeSet xnl = xpath.locationPath(execContext, doc, opPos, null, null, false);
                   if(null != xnl)
                   {
                     mnl.addNodes(xnl.nodeset());
  @@ -201,72 +217,11 @@
       {
         System.out.println("Filespec was bad in connect");
       }
  -            
  -    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;
  +    return results;
     }
  -  */
  -
     
     /**
  -   * 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.
  @@ -274,44 +229,42 @@
      * callback methods are used.
      */
     public XNodeSet union(XPath xpath, XPathSupport execContext, 
  -                           Node context, int opPos) 
  +                        Node context, int opPos,
  +                        NodeCallback callback,
  +                        Object callbackInfo) 
       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.
  +    opPos = xpath.getFirstChildPos(opPos);
   
  -      UnionContext unionContext = new UnionContext(xpath.m_opMap, opPos);
  -      
  -      MutableNodeList mnl = depthStep(xpath, execContext, context, unionContext, 1);
  -    }
  -    else
  -    */
  +    while((xpath.m_opMap[opPos] & XPath.LOCATIONPATHEX_MASK) == xpath.OP_LOCATIONPATH)
       {
  +      int nextOpPos = xpath.getNextOpPos(opPos);
  +
  +      // XNodeSet expr = (XNodeSet)xpath.execute(execContext, context, opPos);
         opPos = xpath.getFirstChildPos(opPos);
  +      MutableNodeList mnl = step(xpath, execContext, context, opPos,
  +                                 callback, callbackInfo, false, false);
  +      XNodeSet expr = (null != mnl) ? new XNodeSet(mnl) : emptyNodeList;
   
  -      while(xpath.m_opMap[opPos] == xpath.OP_LOCATIONPATH)
  +      if(null == resultNodeSet)
         {
  -        int nextOpPos = xpath.getNextOpPos(opPos);
  -
  -        XNodeSet expr = (XNodeSet)xpath.execute(execContext, context, opPos);
  -        if(null == resultNodeSet)
  +        resultNodeSet = expr;
  +      }
  +      else if(expr != emptyNodeList)
  +      {
  +        if(resultNodeSet != emptyNodeList)
           {
  -          resultNodeSet = expr;
  +          MutableNodeList nl = resultNodeSet.mutableNodeset();
  +          nl.addNodesInDocOrder(expr.nodeset(), execContext);
           }
           else
           {
  -          MutableNodeList nl = resultNodeSet.mutableNodeset();
  -          nl.addNodesInDocOrder(expr.nodeset(), execContext);
  +          resultNodeSet = expr;
           }
  -        opPos = nextOpPos;
         }
  +      opPos = nextOpPos;
       }
       
       return resultNodeSet;
  @@ -324,334 +277,39 @@
      * the rest of the LocationPath, and then wraps the NodeList result
      * in an XNodeSet object.
      * @param xpath The xpath that is executing.
  +   * @param execContext The execution context.
      * @param context The current source tree context node.
      * @param opPos The current position in the xpath.m_opMap array.
  +   * @param callback Interface that implements the processLocatedNode method.
  +   * @param callbackInfo Object that will be passed to the processLocatedNode method.
      * @returns the result of the query in an XNodeSet object.
      */
     public XNodeSet locationPath(XPath xpath, XPathSupport execContext, 
  -                               Node context, int opPos) 
  +                               Node context, int opPos,
  +                               NodeCallback callback,
  +                               Object callbackInfo, boolean stopAtFirst) 
       throws org.xml.sax.SAXException
     {    
  -    opPos = xpath.getFirstChildPos(opPos);
       XNodeSet results;
  -    MutableNodeList mnl = step(xpath, execContext, context, opPos);
  -    if(null != mnl)
  +    boolean isSimpleFollowing = (0 != (xpath.m_opMap[opPos] & XPath.LOCATIONPATHEX_MASK));
  +    opPos = xpath.getFirstChildPos(opPos);
  +    MutableNodeList mnl;
  +    try
       {
  -      results = new XNodeSet(mnl);
  +      mnl = step(xpath, execContext, context, opPos,
  +                 callback, callbackInfo, isSimpleFollowing, false);
       }
  -    else
  +    catch(FoundIndex fi)
       {
  -      results = new XNodeSet(new MutableNodeListImpl());
  +      mnl = step(xpath, execContext, context, opPos,
  +                 null, null, false, false);
       }
  -    
  -    return results;
  -  }
  -  
  -  /**
  -   * 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;
  -  }
  +    results = (null != mnl) ? new XNodeSet(mnl) : emptyNodeList;
  +    return results;
  +  }  
       
     /**
  -   * 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,
  @@ -673,157 +331,257 @@
      * @param opPos The current position in the xpath.m_opMap array.
      * @returns a node-set.
      */
  -  protected MutableNodeList step(XPath xpath, XPathSupport execContext, Node context, int opPos) 
  +  protected MutableNodeList step(XPath xpath, XPathSupport execContext, 
  +                                 Node context, int opPos,
  +                                 NodeCallback callback, Object callbackInfo,
  +                                 boolean isSimpleFollowing, boolean stopAtFirst) 
       throws org.xml.sax.SAXException
     {    
       // int endStep = xpath.getNextOpPos(opPos);
       int stepType = xpath.m_opMap[opPos];
  -    int argLen;
  -    MutableNodeList subQueryResults = new MutableNodeListImpl();
  +    int argLen = 200; // dummy val to shut up compiler
  +    MutableNodeList subQueryResults = null;
       MutableNodeList queryResults = null;
       boolean shouldReorder = false;
       boolean continueStepRecursion = true;
       boolean mightHaveToChangeLocators = false;
  -    switch(stepType)
  +    boolean variableArgLen = false;
  +    
  +    if(isSimpleFollowing && (null != callback))
  +      execContext.pushContextNodePosition();
  +        
  +    // If the step has an index predicate, which we won't know until after the 
  +    // predicate is evaluated, and isSimpleFollowing is true, 
  +    // then a FoundIndex exception will be thrown, and we'll try again with 
  +    // a full blown vector search.  This will not be good at all for a few 
  +    // cases, but for the majority cases, the isSimpleFollowing optimization 
  +    // is worth it.
  +    for(int i = 0; i < 2; i++)
       {
  -    case XPath.OP_VARIABLE:
  -    case XPath.OP_EXTFUNCTION:
  -    case XPath.OP_FUNCTION:
  -    case XPath.OP_GROUP:
  -      argLen = findNodeSet(xpath, execContext, context, opPos, 
  -                           stepType, subQueryResults);
  -      mightHaveToChangeLocators = true;
  -      break;
  -    case XPath.FROM_ROOT:
  -      argLen = findRoot(xpath, execContext, context, opPos, stepType, subQueryResults);
  -      break;
  -    case XPath.FROM_PARENT:
  -      argLen = findParent(xpath, execContext, context, opPos, stepType, subQueryResults);
  -      break;
  -    case XPath.FROM_SELF:
  -      argLen = findSelf(xpath, execContext, context, opPos, stepType, subQueryResults);
  -      break;
  -    case XPath.FROM_ANCESTORS:
  -      argLen = findAncestors(xpath, execContext, context, opPos,  stepType, subQueryResults);
  -      shouldReorder = true;
  -      break;
  -    case XPath.FROM_ANCESTORS_OR_SELF:
  -      argLen = findAncestorsOrSelf(xpath, execContext, context, opPos,  stepType, subQueryResults);
  -      shouldReorder = true;
  -      break;
  -    case XPath.MATCH_ATTRIBUTE:
  -      continueStepRecursion = false;
  -      // fall-through on purpose.
  -    case XPath.FROM_ATTRIBUTES:
  -      argLen = findAttributes(xpath, execContext, context, opPos,  stepType, subQueryResults);
  -      break;
  -    case XPath.MATCH_ANY_ANCESTOR:
  -    case XPath.MATCH_IMMEDIATE_ANCESTOR:
  -      continueStepRecursion = false;
  -      // fall-through on purpose.
  -    case XPath.FROM_CHILDREN:
  -      argLen = findChildren(xpath, execContext, context, opPos,  stepType, subQueryResults);
  -      break;
  -    case XPath.FROM_DESCENDANTS:
  -    case XPath.FROM_DESCENDANTS_OR_SELF:
  -      argLen = findDescendants(xpath, execContext, context, opPos,  stepType, subQueryResults);
  -      break;
  -    case XPath.FROM_FOLLOWING:
  -      argLen = findFollowing(xpath, execContext, context, opPos,  stepType, subQueryResults);
  -      break;
  -    case XPath.FROM_FOLLOWING_SIBLINGS:
  -      argLen = findFollowingSiblings(xpath, execContext, context, opPos,  stepType, subQueryResults);
  -      break;
  -    case XPath.FROM_PRECEDING:
  -      argLen = findPreceding(xpath, execContext, context, opPos,  stepType, subQueryResults);
  -      shouldReorder = true;
  -      break;
  -    case XPath.FROM_PRECEDING_SIBLINGS:
  -      argLen = findPrecedingSiblings(xpath, execContext, context, opPos,  stepType, subQueryResults);
  -      shouldReorder = true;
  -      break;
  -    case XPath.FROM_NAMESPACE:
  -      argLen = findNamespace(xpath, execContext, context, opPos,  stepType, subQueryResults);
  -      break;
  -    default:
  -      argLen = findNodesOnUnknownAxis(xpath, execContext, context, opPos,  stepType, subQueryResults);
  -      break;
  +      try
  +      {
  +        switch(stepType)
  +        {
  +        case xpath.OP_VARIABLE:
  +        case xpath.OP_EXTFUNCTION:
  +        case xpath.OP_FUNCTION:
  +        case xpath.OP_GROUP:
  +          subQueryResults = new MutableNodeListImpl();
  +          argLen = findNodeSet(xpath, execContext, context, opPos, 
  +                               stepType, subQueryResults, isSimpleFollowing, stopAtFirst);
  +          mightHaveToChangeLocators = true;
  +          variableArgLen = true;
  +          break;
  +        case XPath.FROM_ROOT:
  +          subQueryResults = findRoot(xpath, execContext, context, opPos, 
  +                                     stepType, subQueryResults, isSimpleFollowing, stopAtFirst);
  +          break;
  +        case XPath.FROM_PARENT:
  +          subQueryResults = findParent(xpath, execContext, context, opPos, 
  +                                       stepType, subQueryResults, isSimpleFollowing, stopAtFirst);
  +          break;
  +        case XPath.FROM_SELF:
  +          subQueryResults = findSelf(xpath, execContext, context, opPos, stepType, subQueryResults,
  +                                     callback, callbackInfo, isSimpleFollowing, stopAtFirst);
  +          break;
  +        case XPath.FROM_ANCESTORS:
  +          subQueryResults = findAncestors(xpath, execContext, context, opPos,  stepType, subQueryResults, isSimpleFollowing, stopAtFirst);
  +          shouldReorder = true;
  +          break;
  +        case XPath.FROM_ANCESTORS_OR_SELF:
  +          subQueryResults = findAncestorsOrSelf(xpath, execContext, context, opPos,  stepType, subQueryResults, isSimpleFollowing, stopAtFirst);
  +          shouldReorder = true;
  +          break;
  +        case xpath.MATCH_ATTRIBUTE:
  +          continueStepRecursion = false;
  +          // fall-through on purpose.
  +        case XPath.FROM_ATTRIBUTES:
  +          subQueryResults = findAttributes(xpath, execContext, context, opPos,  stepType, subQueryResults, isSimpleFollowing, stopAtFirst);
  +          break;
  +        case xpath.MATCH_ANY_ANCESTOR:
  +        case xpath.MATCH_IMMEDIATE_ANCESTOR:
  +          continueStepRecursion = false;
  +          // fall-through on purpose.
  +        case XPath.FROM_CHILDREN:
  +          subQueryResults = findChildren(xpath, execContext, context, opPos,  stepType, subQueryResults,
  +                                         callback, callbackInfo, isSimpleFollowing, stopAtFirst);
  +          break;
  +        case XPath.FROM_DESCENDANTS:
  +        case XPath.FROM_DESCENDANTS_OR_SELF:
  +          subQueryResults = findDescendants(xpath, execContext, context, opPos,  stepType, subQueryResults,
  +                                            callback, callbackInfo, isSimpleFollowing, stopAtFirst);
  +          break;
  +        case XPath.FROM_FOLLOWING:
  +          subQueryResults = findFollowing(xpath, execContext, context, opPos,  stepType, subQueryResults, isSimpleFollowing, stopAtFirst);
  +          break;
  +        case XPath.FROM_FOLLOWING_SIBLINGS:
  +          subQueryResults = findFollowingSiblings(xpath, execContext, context, opPos,  stepType, subQueryResults, isSimpleFollowing, stopAtFirst);
  +          break;
  +        case XPath.FROM_PRECEDING:
  +          subQueryResults = findPreceding(xpath, execContext, context, opPos,  stepType, subQueryResults, isSimpleFollowing, stopAtFirst);
  +          shouldReorder = true;
  +          break;
  +        case XPath.FROM_PRECEDING_SIBLINGS:
  +          subQueryResults = findPrecedingSiblings(xpath, execContext, context, opPos,  stepType, subQueryResults, isSimpleFollowing, stopAtFirst);
  +          shouldReorder = true;
  +          break;
  +        case XPath.FROM_NAMESPACE:
  +          subQueryResults = findNamespace(xpath, execContext, context, opPos,  stepType, subQueryResults, isSimpleFollowing, stopAtFirst);
  +          break;
  +        default:
  +          subQueryResults = findNodesOnUnknownAxis(xpath, execContext, context, opPos,  stepType, subQueryResults, isSimpleFollowing, stopAtFirst);
  +          break;
  +        }
  +
  +        break; // from loop of 2
  +      }
  +      catch(FoundIndex fi)
  +      {
  +        if(isSimpleFollowing && (null != callback))
  +        {
  +          execContext.popContextNodePosition();
  +          subQueryResults = new MutableNodeListImpl();
  +          isSimpleFollowing = false;
  +          stopAtFirst = false;
  +        }
  +        else
  +        {
  +          throw fi;
  +        }
  +      }
  +      finally
  +      {
  +        if(isSimpleFollowing && (null != callback))
  +          execContext.popContextNodePosition();
  +      }
       }
  +    
  +    if(null == subQueryResults)
  +      return null;
  +
  +    if(!variableArgLen)
  +      argLen = xpath.getArgLengthOfStep(opPos)+3;
  +
       opPos += argLen;
       int nextStepType = xpath.m_opMap[opPos];
  -      
  -    NodeList savedContextNodeList = execContext.getContextNodeList();
  -    execContext.setContextNodeList(subQueryResults);
       
  -    if(xpath.OP_PREDICATE == nextStepType)
  +    try
       {
  -      int[] endPredicatesPos = 
  +      execContext.pushContextNodeList(subQueryResults);
  +      
  +      if(xpath.OP_PREDICATE == nextStepType)
         {
  -        -42};
  -      subQueryResults = predicates(xpath, execContext, context, opPos, 
  -                                   subQueryResults, endPredicatesPos);
  -      opPos = endPredicatesPos[0];
  -      nextStepType = xpath.m_opMap[opPos];
  -    }
  +        int[] endPredicatesPos = 
  +        {
  +          -42};
  +        subQueryResults = predicates(xpath, execContext, context, opPos, 
  +                                     subQueryResults, endPredicatesPos);
  +        opPos = endPredicatesPos[0];
  +        nextStepType = xpath.m_opMap[opPos];
  +      }
         
  -    XLocator xlocator = this;
  -    if((xpath.ENDOP != nextStepType) && continueStepRecursion)
  -    {
  -      int nContexts = subQueryResults.getLength();
  -      for(int i = 0; i < nContexts; i++)
  +      if(null == subQueryResults)
  +        return null;
  +      
  +      XLocator xlocator = this;
  +      if((xpath.ENDOP != nextStepType) && continueStepRecursion)
         {
  -        Node node = subQueryResults.item(i);
  -        if(null != node)
  +        int nContexts = subQueryResults.getLength();
  +        for(int i = 0; i < nContexts; i++)
           {
  -          if(mightHaveToChangeLocators)
  -          {
  -            xlocator = execContext.getXLocatorFromNode(node);
  -          }
  -          MutableNodeList mnl = step(xpath, execContext, node, opPos);
  -          if(queryResults == null)
  +          Node node = subQueryResults.item(i);
  +          if(null != node)
             {
  -            queryResults = mnl;
  -          }
  -          else
  -          {
  -            queryResults.addNodesInDocOrder(mnl, execContext);
  +            if(mightHaveToChangeLocators)
  +            {
  +              xlocator = execContext.getXLocatorFromNode(node);
  +            }
  +            MutableNodeList mnl = step(xpath, execContext, node, opPos, null, null, false, false);
  +            if((null != mnl) && mnl != this.emptyNodeList)
  +            {
  +              if(queryResults == null)
  +              {
  +                queryResults = mnl;
  +              }
  +              else
  +              {
  +                queryResults.addNodesInDocOrder(mnl, execContext);
  +              }
  +            }
             }
           }
         }
  -      if(null == queryResults)
  +      else
         {
  -        queryResults = new MutableNodeListImpl();
  +        if(shouldReorder)
  +        {
  +          queryResults = new MutableNodeListImpl();
  +          queryResults.addNodesInDocOrder(subQueryResults, execContext);
  +        }
  +        else
  +        {
  +          queryResults = subQueryResults;
  +        }
         }
       }
  -    else
  +    finally
       {
  -      if(shouldReorder)
  -      {
  -        queryResults = new MutableNodeListImpl();
  -        queryResults.addNodesInDocOrder(subQueryResults, execContext);
  -      }
  -      else
  -      {
  -        queryResults = subQueryResults;
  -      }
  +      execContext.popContextNodeList();
       }
  -    execContext.setContextNodeList(savedContextNodeList);
  +
       return queryResults;
     }
     
     /**
  +   * Add a node to a node list, but lazily create the node list if 
  +   * it doesn't already exist.
  +   */
  +  private final MutableNodeList addNode(MutableNodeList subQueryResults, Node node)
  +  {
  +    if(null == subQueryResults)
  +      subQueryResults = new MutableNodeListImpl(node);
  +    else
  +      subQueryResults.addNode(node);
  +    return subQueryResults;
  +  }
  +  
  +  /**
  +   * Add a node to a node list, but lazily create the node list if 
  +   * it doesn't already exist.
  +   */
  +  private final MutableNodeList addNodeInDocOrder(XPathSupport execContext, MutableNodeList subQueryResults, Node node)
  +  {
  +    if(null == subQueryResults)
  +      subQueryResults = new MutableNodeListImpl(node);
  +    else
  +      subQueryResults.addNodeInDocOrder(node, execContext);
  +    return subQueryResults;
  +  }
  +  
  +  /**
  +   * Add a node to the ContextNodeList, if we're doing depth-first 
  +   * traversal.
  +   */
  +  void addToContextNodeList(XPathSupport execContext, Node n)
  +  {
  +  }
  +
  +  
  +  /**
      * 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.
      * @param opPos The current position in the xpath.m_opMap array.
  -   * @param stepType Value of xpath.FROM_SELF.
  +   * @param stepType Value of XPath.FROM_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 findSelf(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  -                             int stepType, MutableNodeList subQueryResults)
  +  protected MutableNodeList findSelf(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  +                                     int stepType, MutableNodeList subQueryResults,
  +                                     NodeCallback callback, Object callbackInfo,
  +                                     boolean isSimpleFollowing, boolean stopAtFirst)
       throws org.xml.sax.SAXException
     {
       int argLen = xpath.getArgLengthOfStep(opPos);
  @@ -832,14 +590,38 @@
       {
         if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, context, opPos, argLen, stepType))
         {
  -        subQueryResults.addNode(context);
  +        // subQueryResults.addNode(context);
  +        if(isSimpleFollowing && (null != callback))
  +        {
  +          execContext.incrementContextNodePosition(context);
  +          if(predicate(xpath, execContext, context, opPos+argLen))
  +          {
  +            callback.processLocatedNode(execContext, context, callbackInfo);
  +          }
  +        }
  +        else
  +        {
  +          subQueryResults = addNode(subQueryResults, context);
  +        }
         }
       }
       else
       {
  -      subQueryResults.addNode(context);
  +      // subQueryResults.addNode(context);
  +      if(isSimpleFollowing && (null != callback))
  +      {
  +        execContext.incrementContextNodePosition(context);
  +        if(predicate(xpath, execContext, context, opPos+argLen))
  +        {
  +          callback.processLocatedNode(execContext, context, callbackInfo);
  +        }
  +      }
  +      else
  +      {
  +        subQueryResults = addNode(subQueryResults, context);
  +      }
       }
  -    return argLen+3;
  +    return subQueryResults;
     }
     
     /**
  @@ -848,14 +630,15 @@
      * @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_ATTRIBUTES.
  +   * @param stepType Value of XPath.FROM_ATTRIBUTES.
      * @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 findAttributes(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  -                                 int stepType, MutableNodeList subQueryResults)
  +  protected MutableNodeList findAttributes(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  +                                           int stepType, MutableNodeList subQueryResults,
  +                                           boolean isSimpleFollowing, boolean stopAtFirst)
       throws org.xml.sax.SAXException
     {
       int argLen = xpath.getArgLengthOfStep(opPos);
  @@ -871,12 +654,13 @@
             Attr attr = (Attr)attributeList.item(j);
             if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, attr, opPos, argLen, stepType))
             {
  -            subQueryResults.addNode(attr);
  +            subQueryResults = addNode(subQueryResults, attr);
  +            // If we have an attribute name here, we can quit.
             }
           }
         }
       }
  -    return argLen+3;
  +    return subQueryResults;
     }
   
     /**
  @@ -885,14 +669,17 @@
      * @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_CHILDREN.
  +   * @param stepType Value of XPath.FROM_CHILDREN.
      * @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 findChildren(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  -                               int stepType, MutableNodeList subQueryResults)
  +  protected MutableNodeList findChildren(XPath xpath, XPathSupport execContext, Node context, 
  +                                         int opPos, 
  +                                         int stepType, MutableNodeList subQueryResults,
  +                                         NodeCallback callback, Object callbackInfo,
  +                                         boolean isSimpleFollowing, boolean stopAtFirst)
       throws org.xml.sax.SAXException
     {
       int argLen = xpath.getArgLengthOfStep(opPos);
  @@ -908,7 +695,21 @@
           {
             // or else call execute method.  If no execute method,
             // add the node.
  -          subQueryResults.addNode(c);
  +          // subQueryResults.addNode(c);
  +          if(isSimpleFollowing && (null != callback))
  +          {
  +            execContext.incrementContextNodePosition(c);
  +            if(predicate(xpath, execContext, c, opPos+argLen))
  +            {
  +              callback.processLocatedNode(execContext, c, callbackInfo);
  +              if(stopAtFirst)
  +                break;
  +            }
  +          }
  +          else
  +          {
  +            subQueryResults = addNode(subQueryResults, c);
  +          }
           }
           c = c.getNextSibling();
         }
  @@ -922,12 +723,26 @@
           Node c = children.item(i);
           if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, c, opPos, argLen, stepType))
           {
  -          subQueryResults.addNode(c);
  +          // subQueryResults.addNode(c);
  +          if(isSimpleFollowing && (null != callback))
  +          {
  +            execContext.incrementContextNodePosition(c);
  +            if(predicate(xpath, execContext, c, opPos+argLen))
  +            {
  +              callback.processLocatedNode(execContext, c, callbackInfo);
  +              if(stopAtFirst)
  +                break;
  +            }
  +          }
  +          else
  +          {
  +            subQueryResults = addNode(subQueryResults, c);
  +          }
           }
           c = c.getNextSibling();
         }
       }
  -    return argLen+3;
  +    return subQueryResults;
     }
     
     /**
  @@ -937,14 +752,17 @@
      * @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_DESCENDANTS or xpath.FROM_DESCENDANTS_OR_SELF.
  +   * @param stepType Value of XPath.FROM_DESCENDANTS or XPath.FROM_DESCENDANTS_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 findDescendants(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  -                                int stepType, MutableNodeList subQueryResults)
  +  protected MutableNodeList findDescendants(XPath xpath, XPathSupport execContext, 
  +                                            Node context, int opPos, 
  +                                            int stepType, MutableNodeList subQueryResults,
  +                                            NodeCallback callback, Object callbackInfo,
  +                                            boolean isSimpleFollowing, boolean stopAtFirst)
       throws org.xml.sax.SAXException
     {
       int argLen = xpath.getArgLengthOfStep(opPos);
  @@ -970,11 +788,25 @@
       {
         while(null != pos)
         {                   
  -        if((stepType == xpath.FROM_DESCENDANTS_OR_SELF) || (context != pos))
  +        if((stepType == XPath.FROM_DESCENDANTS_OR_SELF) || (context != pos))
           {
             if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, pos, opPos, argLen, stepType))
             {
  -            subQueryResults.addNode(pos);
  +            // subQueryResults.addNode(pos);
  +            if(isSimpleFollowing && (null != callback))
  +            {
  +              execContext.incrementContextNodePosition(pos);
  +              if(predicate(xpath, execContext, pos, opPos+argLen))
  +              {
  +                callback.processLocatedNode(execContext, pos, callbackInfo);
  +                if(stopAtFirst)
  +                  break;
  +              }
  +            }
  +            else
  +            {
  +              subQueryResults = addNode(subQueryResults, pos);
  +            }
             }
           }
           Node nextNode = pos.getFirstChild();
  @@ -1006,11 +838,24 @@
           context = pos;
           while(null != pos)
           {                   
  -          if((stepType == xpath.FROM_DESCENDANTS_OR_SELF) || (!context.equals( pos )))
  +          if((stepType == XPath.FROM_DESCENDANTS_OR_SELF) || (!context.equals( pos )))
             {
               if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, pos, opPos, argLen, stepType))
               {
  -              subQueryResults.addNode(pos);
  +              if(isSimpleFollowing && (null != callback))
  +              {
  +                execContext.incrementContextNodePosition(pos);
  +                if(predicate(xpath, execContext, pos, opPos+argLen))
  +                {
  +                  callback.processLocatedNode(execContext, pos, callbackInfo);
  +                  if(stopAtFirst)
  +                    break;
  +                }
  +              }
  +              else
  +              {
  +                subQueryResults = addNode(subQueryResults, pos);
  +              }
               }
             }
             Node nextNode = pos.getFirstChild();
  @@ -1033,7 +878,7 @@
           }
         }
       }
  -    return argLen+3;
  +    return subQueryResults;
     }
   
     /**
  @@ -1050,14 +895,15 @@
      * @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_FOLLOWING.
  +   * @param stepType Value of XPath.FROM_FOLLOWING.
      * @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 findFollowing(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  -                                int stepType, MutableNodeList subQueryResults)
  +  protected MutableNodeList findFollowing(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  +                                          int stepType, MutableNodeList subQueryResults,
  +                                          boolean isSimpleFollowing, boolean stopAtFirst)
       throws org.xml.sax.SAXException
     {
       int argLen = xpath.getArgLengthOfStep(opPos);
  @@ -1073,7 +919,7 @@
         {
           if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, pos, opPos, argLen, stepType))
           {
  -          subQueryResults.addNodeInDocOrder(pos, execContext);
  +          subQueryResults = addNodeInDocOrder(execContext, subQueryResults, pos);
           }
           nextNode = pos.getFirstChild();
         }
  @@ -1096,7 +942,7 @@
         }
         pos = nextNode;
       }
  -    return argLen+3;
  +    return subQueryResults;
     }
     
   
  @@ -1107,14 +953,15 @@
      * @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_FOLLOWING_SIBLINGS.
  +   * @param stepType Value of XPath.FROM_FOLLOWING_SIBLINGS.
      * @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 findFollowingSiblings(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  -                                      int stepType, MutableNodeList subQueryResults)
  +  protected MutableNodeList findFollowingSiblings(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  +                                                  int stepType, MutableNodeList subQueryResults,
  +                                                  boolean isSimpleFollowing, boolean stopAtFirst)
       throws org.xml.sax.SAXException
     {
       int argLen = xpath.getArgLengthOfStep(opPos);
  @@ -1125,11 +972,11 @@
       {                   
         if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, pos, opPos, argLen, stepType))
         {
  -        subQueryResults.addNode(pos);
  +        subQueryResults = addNode(subQueryResults, pos);
         }
         pos = pos.getNextSibling();
       }
  -    return argLen+3;
  +    return subQueryResults;
     }
     
     
  @@ -1147,19 +994,20 @@
      * or end of step).
      */
     protected int findNodeSet(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  -                              int stepType, MutableNodeList subQueryResults)
  +                            int stepType, MutableNodeList subQueryResults,
  +                            boolean isSimpleFollowing, boolean stopAtFirst)
       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];
  +    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];
     }
     
     /**
  @@ -1167,14 +1015,15 @@
      * @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 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)
  +  protected MutableNodeList findRoot(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  +                                     int stepType, MutableNodeList subQueryResults,
  +                                     boolean isSimpleFollowing, boolean stopAtFirst)
       throws org.xml.sax.SAXException
     {
       int argLen = xpath.getArgLengthOfStep(opPos);
  @@ -1182,8 +1031,8 @@
   
       Document docContext = (Node.DOCUMENT_NODE == context.getNodeType()) 
                             ? (Document)context : context.getOwnerDocument();
  -    subQueryResults.addNode(docContext);
  -    return argLen+3;
  +    subQueryResults = addNode(subQueryResults, docContext);
  +    return subQueryResults;
     }
     
     /**
  @@ -1191,14 +1040,15 @@
      * @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 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)
  +  protected MutableNodeList findParent(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  +                                       int stepType, MutableNodeList subQueryResults,
  +                                       boolean isSimpleFollowing, boolean stopAtFirst)
       throws org.xml.sax.SAXException
     {
       context = execContext.getParentOfNode(context);
  @@ -1210,15 +1060,15 @@
         {
           if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, context, opPos, argLen, stepType))
           {
  -          subQueryResults.addNode(context);
  +          subQueryResults = addNode(subQueryResults, context);
           }
         }
         else
         {
  -        subQueryResults.addNode(context);
  +        subQueryResults = addNode(subQueryResults, context);
         }
       }
  -    return argLen+3;
  +    return subQueryResults;
     }
     
     /**
  @@ -1226,14 +1076,15 @@
      * @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 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)
  +  protected MutableNodeList findAncestors(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  +                                          int stepType, MutableNodeList subQueryResults,
  +                                          boolean isSimpleFollowing, boolean stopAtFirst)
       throws org.xml.sax.SAXException
     {
       context = execContext.getParentOfNode(context);
  @@ -1243,27 +1094,28 @@
       {
         if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, context, opPos, argLen, stepType))
         {
  -        subQueryResults.addNode(context);
  +        subQueryResults = addNode(subQueryResults, context);
         }
         context = execContext.getParentOfNode(context);
       }
  -    return argLen+3;
  +    return subQueryResults;
     }
  - 
  +  
     /**
      * 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 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)
  +  protected MutableNodeList findAncestorsOrSelf(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  +                                                int stepType, MutableNodeList subQueryResults,
  +                                                boolean isSimpleFollowing, boolean stopAtFirst)
       throws org.xml.sax.SAXException
     {
       int argLen = xpath.getArgLengthOfStep(opPos);
  @@ -1272,11 +1124,11 @@
       {
         if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, context, opPos, argLen, stepType))
         {
  -        subQueryResults.addNode(context);
  +        subQueryResults = addNode(subQueryResults, context);
         }
         context = execContext.getParentOfNode(context);
       }
  -    return argLen+3;
  +    return subQueryResults;
     }
   
     /**
  @@ -1293,14 +1145,15 @@
      * @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_PRECEDING.
  +   * @param stepType Value of XPath.FROM_PRECEDING.
      * @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 findPreceding(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  -                                int stepType, MutableNodeList subQueryResults)
  +  protected MutableNodeList findPreceding(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  +                                          int stepType, MutableNodeList subQueryResults,
  +                                          boolean isSimpleFollowing, boolean stopAtFirst)
       throws org.xml.sax.SAXException
     {
       int argLen = xpath.getArgLengthOfStep(opPos);
  @@ -1332,7 +1185,10 @@
           
           if(!isParent)
           {
  -          subQueryResults.insertNode(pos, 0);
  +          if(null == subQueryResults)
  +            subQueryResults = new MutableNodeListImpl(pos);
  +          else
  +            subQueryResults.insertNode(pos, 0);
           }
         }
         Node nextNode = pos.getFirstChild();
  @@ -1353,7 +1209,7 @@
         }
         pos = nextNode;
       }
  -    return argLen+3;
  +    return subQueryResults;
     }
     
     /**
  @@ -1362,14 +1218,15 @@
      * @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_PRECEDING_SIBLINGS.
  +   * @param stepType Value of XPath.FROM_PRECEDING_SIBLINGS.
      * @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 findPrecedingSiblings(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  -                                      int stepType, MutableNodeList subQueryResults)
  +  protected MutableNodeList findPrecedingSiblings(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  +                                                  int stepType, MutableNodeList subQueryResults,
  +                                                  boolean isSimpleFollowing, boolean stopAtFirst)
       throws org.xml.sax.SAXException
     {
       int argLen = xpath.getArgLengthOfStep(opPos);
  @@ -1380,11 +1237,11 @@
       {                   
         if(xpath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, pos, opPos, argLen, stepType))
         {
  -        subQueryResults.addNode(pos);
  +        subQueryResults = addNode(subQueryResults, pos);
         }
         pos = pos.getPreviousSibling();
       }
  -    return argLen+3;
  +    return subQueryResults;
     }
     
     /**
  @@ -1392,20 +1249,21 @@
      * @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_NAMESPACE.
  +   * @param stepType Value of XPath.FROM_NAMESPACE.
      * @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 findNamespace(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  -                              int stepType, MutableNodeList subQueryResults)
  +  protected MutableNodeList findNamespace(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  +                                          int stepType, MutableNodeList subQueryResults,
  +                                          boolean isSimpleFollowing, boolean stopAtFirst)
       throws org.xml.sax.SAXException
     {
       int argLen = xpath.getArgLengthOfStep(opPos);
       opPos = xpath.getFirstChildPosOfStep(opPos);
       xpath.error(context, XPATHErrorResources.ER_NAMESPACEAXIS_NOT_IMPLEMENTED); //"namespace axis not implemented yet!");
  -    return argLen+3;
  +    return subQueryResults;
     }
     
     /**
  @@ -1413,20 +1271,54 @@
      * @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_NAMESPACE.
  +   * @param stepType Value of XPath.FROM_NAMESPACE.
      * @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 findNodesOnUnknownAxis(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  -                              int stepType, MutableNodeList subQueryResults)
  +  protected MutableNodeList findNodesOnUnknownAxis(XPath xpath, XPathSupport execContext, Node context, int opPos, 
  +                                                   int stepType, MutableNodeList subQueryResults,
  +                                                   boolean isSimpleFollowing, boolean stopAtFirst)
       throws org.xml.sax.SAXException
     {
       int argLen = xpath.getArgLengthOfStep(opPos);
       opPos = xpath.getFirstChildPosOfStep(opPos);
  -	xpath.error(context, XPATHErrorResources.ER_UNKNOWN_AXIS, new Object[] {Integer.toString(stepType)}); //"unknown axis: "+stepType);
  -    return argLen+3;
  +    xpath.error(context, XPATHErrorResources.ER_UNKNOWN_AXIS, new Object[] {Integer.toString(stepType)}); //"unknown axis: "+stepType);
  +    return subQueryResults;
  +  }
  +
  +  /**
  +   * Execute a single predicate for a single node.
  +   * @returns True if the node should not be filtered.
  +   */
  +  protected boolean predicate(XPath xpath, XPathSupport execContext, Node context, int opPos) 
  +    throws org.xml.sax.SAXException
  +  {
  +    boolean shouldNotFilter = true;
  +
  +    int nextStepType = xpath.m_opMap[opPos];
  +    if(xpath.OP_PREDICATE == nextStepType)
  +    {
  +      execContext.pushDummyXPathContext();
  +      try
  +      {
  +        XObject pred = xpath.predicate(execContext, context, opPos);
  +        if(XObject.CLASS_NUMBER == pred.getType())
  +        {
  +          throw new FoundIndex(); // Ugly, but... see comment in the Step function.
  +        }
  +        else if(!pred.bool())
  +        {
  +          shouldNotFilter = false;
  +        }
  +      }
  +      finally
  +      {
  +        execContext.popXPathContext();
  +      }
  +    }
  +    return shouldNotFilter;
     }
   
   
  @@ -1472,21 +1364,23 @@
         {
           // This will reconstruct the node list without the nulls.
           subQueryResults = new MutableNodeListImpl(subQueryResults);
  -     
  -        execContext.setContextNodeList(subQueryResults);
  +        
  +        execContext.popContextNodeList();
  +        execContext.pushContextNodeList(subQueryResults);
           // Don't break, loop 'till end so that opPos will be set to end.
           // if(0 == subQueryResults.getLength())
           //  break;
         }
       }
  -    endPredicatesPos[0] = opPos;
  +    if(null != endPredicatesPos)
  +      endPredicatesPos[0] = opPos;
       if(hasNulls)
       {
         subQueryResults = new MutableNodeListImpl(subQueryResults);
       }
       return subQueryResults;
     }
  -    
  +  
     /**
      * Execute a a location path pattern.  This will return a score
      * of MATCH_SCORE_NONE, MATCH_SCORE_NODETEST, 
  @@ -1501,7 +1395,9 @@
       throws org.xml.sax.SAXException
     {    
       opPos = xpath.getFirstChildPos(opPos);
  -    double[] scoreHolder = {xpath.MATCH_SCORE_NONE};
  +    double[] scoreHolder = 
  +    {
  +      xpath.MATCH_SCORE_NONE};
       stepPattern(xpath, execContext, context, opPos, scoreHolder);
       return scoreHolder[0];
     }
  @@ -1578,7 +1474,7 @@
         {
           argLen = xpath.getArgLengthOfStep(opPos);
           opPos = xpath.getFirstChildPosOfStep(opPos);
  -        score = nodeTest(xpath, execContext, context, opPos, argLen, xpath.FROM_ATTRIBUTES);
  +        score = nodeTest(xpath, execContext, context, opPos, argLen, XPath.FROM_ATTRIBUTES);
           break;
         }
       case XPath.MATCH_ANY_ANCESTOR:
  @@ -1662,7 +1558,7 @@
           // easiest way.
           execContext.setThrowFoundIndex(false);
           Node parentContext = execContext.getParentOfNode(context);
  -        MutableNodeList mnl = step(xpath, execContext, parentContext, startOpPos);
  +        MutableNodeList mnl = step(xpath, execContext, parentContext, startOpPos, null, null, false, false);
           int nNodes = mnl.getLength();
           score = xpath.MATCH_SCORE_NONE;
           for(int i = 0; i < nNodes; i++)
  @@ -1681,7 +1577,7 @@
       if((scoreHolder[0] == xpath.MATCH_SCORE_NONE) || 
          (score == xpath.MATCH_SCORE_NONE))
         scoreHolder[0] = score;
  -            
  +    
       return (score == xpath.MATCH_SCORE_NONE) ? null : context;
     }
   
  @@ -1711,7 +1607,7 @@
         break;
       case XPath.NODETYPE_TEXT:
         score = (((Node.CDATA_SECTION_NODE == nodeType) 
  -             || (Node.TEXT_NODE == nodeType)) &&
  +                || (Node.TEXT_NODE == nodeType)) &&
                  (!execContext.shouldStripSourceNode(context)))
                 ? xpath.MATCH_SCORE_NODETEST : xpath.MATCH_SCORE_NONE;
         break;
  @@ -1744,7 +1640,7 @@
            || (Node.TEXT_NODE == nodeType))
         {
           score = (!execContext.shouldStripSourceNode(context))
  -                 ? xpath.MATCH_SCORE_NODETEST : xpath.MATCH_SCORE_NONE;
  +                ? xpath.MATCH_SCORE_NODETEST : xpath.MATCH_SCORE_NONE;
         }
         else
         {
  @@ -1759,6 +1655,9 @@
         
       case XPath.NODENAME:
         {
  +        if(!((Node.ATTRIBUTE_NODE == nodeType) || (Node.ELEMENT_NODE == nodeType)))
  +          return xpath.MATCH_SCORE_NONE;
  +                                        
           boolean test;
           int queueIndex = xpath.m_opMap[opPos];
           String targetNS = (queueIndex >= 0) ? (String)xpath.m_tokenQueue[xpath.m_opMap[opPos]]
  @@ -1811,7 +1710,7 @@
             switch(nodeType)
             {
             case Node.ATTRIBUTE_NODE:
  -            if(stepType == xpath.FROM_ATTRIBUTES)
  +            if(stepType == XPath.FROM_ATTRIBUTES)
               {            
                 
                 if(xpath.ELEMWILDCARD == queueIndex)
  @@ -1823,7 +1722,7 @@
                                 || attrName.equals("xmlns"))))
                             ? xpath.MATCH_SCORE_NODETEST 
                               : xpath.MATCH_SCORE_NONE;
  -               }
  +                }
                   else
                   {
                     score = xpath.MATCH_SCORE_NODETEST;
  @@ -1844,7 +1743,7 @@
               break;
   
             case Node.ELEMENT_NODE:
  -            if(stepType != xpath.FROM_ATTRIBUTES)
  +            if(stepType != XPath.FROM_ATTRIBUTES)
               {
                 if(xpath.ELEMWILDCARD == queueIndex)
                 {
  @@ -1866,7 +1765,7 @@
               
             default:
               // Trying to match on anything else causes nasty bugs.
  -              score  = xpath.MATCH_SCORE_NONE;
  +            score  = xpath.MATCH_SCORE_NONE;
               break;
   
             } // end switch(nodeType)
  
  
  
  1.2       +412 -62   xml-xalan/src/org/apache/xalan/xpath/UnionContext.java
  
  Index: UnionContext.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xpath/UnionContext.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- UnionContext.java	1999/12/13 08:06:01	1.1
  +++ UnionContext.java	2000/02/13 16:42:41	1.2
  @@ -59,16 +59,77 @@
   import org.apache.xalan.xpath.xml.IntStack;
   
   /**
  - * Tracks multiple stacks of opcodes positions.
  + * Tracks multiple stacks of opcodes positions. This tracks a 
  + * a table of "fingers" that point to various positions within
  + * a given opcode list.  As each node is encountered, a set 
  + * of fingers is pushed on the stack, that corresponds to 
  + * the set of node tests that need to be done for that node.
  + * This is actually implemented as a stack of stacks of ints.
    */
   public class UnionContext
   {
  -  static final int MAXPATHS = 32;
  -  IntStack[] m_stacks = new IntStack[MAXPATHS];
  -  IntStack[] m_posStacks = new IntStack[MAXPATHS];
  +  /**
  +   * The initial number of columns in the table.
  +   */
  +  static final int INITIALTABLEWIDTH = 32;
  +
  +  /**
  +   * The amount to increase the stack size by.
  +   */
  +  static final int BLOCKINCREASE = 32;
  +
  +  /**
  +   * To avoid having to make a stack of objects, or multiple 
  +   * int stacks, each stack value is composed of multiple ints.
  +   * In other words, if a step is pushed onto the stack, the 
  +   * top of the stack value will increase this amount.
  +   */
  +  static final int SLOTSPERVALUE = 3;
  +  
  +  /**
  +   * The position of the "finger" (i.e. the opcode position
  +   * in the opcode map).
  +   */
  +  static final int SLOT_FINGER = 0;
  +  
  +  /**
  +   * The count for the given node, to be used for 
  +   * the position() function and the like.
  +   */
  +  static final int SLOT_COUNT = SLOT_FINGER+1;
  +  
  +  /**
  +   * The position for an int that can hold binary 
  +   * flags, for instance an axes flag for following:: 
  +   * and descendents::.
  +   */
  +  static final int SLOT_FLAGS = SLOT_COUNT+1;
  + 
  +  /**
  +   * Flag to tell if the next step should walk children.
  +   */
  +  static final int FLAG_SHOULDWALKCHILDREN = (0x00000001 << 0);
  +
  +  /**
  +   * Flag to tell if the next step should walk attributes.
  +   */
  +  static final int FLAG_SHOULDWALKATTRIBUTES = (0x00000001 << 1);
  +
  +  /**
  +   * Flag to tell if the next step should walk following siblings.
  +   */
  +  static final int FLAG_SHOULDWALKFOLLOWINGSIBLINGS = (0x00000001 << 2);
  +
  +  /**
  +   * This flag must be set down to the bottom of the stack. It tells 
  +   * that all following nodes must be tested.
  +   */
  +  static final int FLAG_SHOULDWALKFOLLOWING = (0x00000001 << 3);
  +
  +  IntStack[] m_stacks = new IntStack[INITIALTABLEWIDTH*SLOTSPERVALUE];
     int m_stackCount;
   
  -  public static final int PSUEDO_POS_FOUNDNODE = -10000;
  +  public static final int PSUEDO_POS_NULL = -10000;
     public static final int PSUEDO_OP_FOUNDNODE = -10000;
   
     /**
  @@ -83,9 +144,9 @@
       {
         pushUnionPath(opMap, opPos);
       }
  -    else if(XPath.OP_LOCATIONPATH == op)
  +    else if(XPath.OP_LOCATIONPATH == (op & XPath.LOCATIONPATHEX_MASK))
       {
  -      pushLocationPath(0, opMap, opPos);
  +      pushLocationPath(opPos);
       }
       else
       {
  @@ -110,56 +171,125 @@
     }
     
     /**
  +   * Get the size of the of the first stack, which should normally 
  +   * be the size of all the stacks, once construction of any 
  +   * given state is completed.  If there are no stacks, return 0.
  +   */
  +  int size()
  +  {
  +    return (m_stackCount > 0) ? m_stacks[0].size() : 0;
  +  }
  +  
  +  /**
  +   * Ensure there's enough room for the given index.
  +   */
  +  void ensureNewSpace(int number)
  +  {
  +    if((m_stackCount+number) >= m_stacks.length)
  +    {
  +      IntStack[] newStacks = new IntStack[m_stackCount+BLOCKINCREASE];
  +      System.arraycopy(m_stacks, 0, newStacks, 0, m_stackCount);
  +    }
  +  }
  +  
  +  /**
      * Add a new stack and set the stack count 
  -   * to which+1.
  +   * to m_stackCount+1.
      */
  -  private final void addNewLocationPath(int which)
  +  private int addNewLocationPath()
     {
  -    m_stacks[which] = new IntStack();
  -    m_posStacks[which] = new IntStack();
  -    setLocationPathCount(which+1);
  +    ensureNewSpace(1);
  +    int pos = m_stackCount;
  +    m_stackCount+=1;
  +    m_stacks[pos] = new IntStack();
  +    return pos;
  +  }
  +    
  +  /**
  +   * Add a new stack and set the stack count 
  +   * to which+1, set the stack top to equal the 
  +   * other stack's tops+1, and copy opCodePos,  nodePos, and flags
  +   * down the stack.
  +   * @return the position of the new stack.
  +   */
  +  int addNewLocationPath(int opCodePos, int nodePos, int flags)
  +  {
  +    int which = addNewLocationPath();
  +    int depth = size();
  +    IntStack stack = this.m_stacks[which];
  +    for(int i = 0; i < depth; i += 3)
  +    {
  +      stack.addElement(opCodePos);
  +      stack.addElement(nodePos);
  +      stack.addElement(flags);
  +    }
  +    stack.addElement(opCodePos);
  +    stack.addElement(nodePos);
  +    stack.addElement(flags);
  +    return which;
     }
     
     /**
  -   * Push the 
  +   * Add a new stack and set the stack count 
  +   * to which+1, set the stack top to equal the 
  +   * other stack's tops+1, copy opCodePos,  nodePos, and flags
  +   * down the stack, and copy topOpCodePos, topFlags, and 
  +   * topFlags to the top of the stack.
  +   */
  +  final int addNewLocationPath(int topOpCodePos, int topNodePos, int topFlags,
  +                                int opCodePos, int nodePos, int flags)
  +  {
  +    int which = addNewLocationPath();
  +    int depth = size();
  +    IntStack stack = this.m_stacks[which];
  +    for(int i = 0; i < depth; i += 3)
  +    {
  +      stack.addElement(opCodePos);
  +      stack.addElement(nodePos);
  +      stack.addElement(flags);
  +    }
  +    stack.addElement(topOpCodePos);
  +    stack.addElement(topNodePos);
  +    stack.addElement(topFlags);
  +    return which;
  +  }
  +  
  +  /**
  +   * Add a new stack and set the stack count 
  +   * to which+1, set the stack top to equal the 
  +   * other stack's tops+1, copy opCodePos,  nodePos, and flags
  +   * down the stack, and copy topOpCodePos, topFlags, and 
  +   * topFlags to the top of the stack.
      */
  -  void pushLocationPath(int which, int[] opMap, int opPos)
  +  final boolean setFlagsIfOpPos(int opCodePos, int flags)
     {
  -    addNewLocationPath(which);
  -    opPos = XPath.getFirstChildPos(opPos);
  -    push(which, opPos, 1);
  -    /*
  -    while(opPos < posOfLastOp)
  -    {
  -      // step
  -      int stepType = xpath.m_opMap[opPos];
  -      
  -      switch(stepType)
  +    int n = this.m_stackCount;
  +    for(int i = 0; i < this.m_stackCount; i++)
  +    {
  +      IntStack stack=m_stacks[i];
  +      int pos = (stack.size() - SLOTSPERVALUE)+SLOT_FINGER;
  +      if(stack.elementAt(pos) == opCodePos)
         {
  -      case xpath.FROM_ATTRIBUTES: // ?
  -        m_shouldWalkAttributes = true;
  -      case xpath.FROM_CHILDREN:
  -      case xpath.FROM_DESCENDANTS:
  -        break;
  -      case xpath.FROM_SELF:
  -      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:
  -        System.out.println("ERROR! Should only find forward axes!");
  +        pos = (stack.size() - SLOTSPERVALUE)+SLOT_FLAGS;
  +        stack.setElementAt(flags, pos);
  +        return true;
         }
  -
  -      opPos = XPath.getNextOpPos(opMap, opPos);
       }
  -    if(xpath.m_opMap[opPos] != xpath.ENDOP)
  -    {
  -      System.out.println("ERROR! Could not find ENDOP after OP_LOCATIONPATH");
  -    }
  -    */
  +    return false;
     }
     
     /**
  +   * Push the a new location path
  +   */
  +  int pushLocationPath(int opPos)
  +  {
  +    int which = addNewLocationPath();
  +    opPos = XPath.getFirstChildPos(opPos);
  +    push(which, opPos, 0 /* start count */, 0 /*flags */);
  +    return which;
  +  }
  +  
  +  /**
      * Walk a union pattern and push each of the positions 
      * of the first child of the location steps.
      */
  @@ -167,39 +297,207 @@
     {
       opPos+=2;
       
  -    for(int i = 0; opMap[opPos] == XPath.OP_LOCATIONPATH; i++)
  +    for(int i = 0; 
  +        (opMap[opPos] & XPath.LOCATIONPATHEX_MASK) == XPath.OP_LOCATIONPATH; i++)
       {
         int nextOpPos = XPath.getNextOpPos(opMap, opPos);
  -      pushLocationPath(i, opMap, opPos);
  +      pushLocationPath(opPos);
         opPos = nextOpPos;
       }
     }
     
     /**
  -   * Set the index position for a node, associated with 
  -   * the given LocationPath.
  +   * Set the given flag which is associated with a traversal 
  +   * from the tested node.
      */
  -  void setNodePosition(int which, int nodePos)
  +  void setOpPos(int which, int finger)
     {
  -    m_posStacks[which].setTop(nodePos);
  +    IntStack stack=m_stacks[which];
  +    int pos = (stack.size() - SLOTSPERVALUE)+SLOT_FINGER;
  +    stack.setElementAt(finger, pos);
     }
  +  
  +  /**
  +   * Set the given flag which is associated with a traversal 
  +   * from the tested node.
  +   */
  +  void setFlags(int which, int flag)
  +  {
  +    IntStack stack=m_stacks[which];
  +    int pos = (stack.size() - SLOTSPERVALUE)+SLOT_FLAGS;
  +    stack.setElementAt(flag, pos);
  +  }
  +  
  +  /**
  +   * Set the given flag(s) which are associated with a traversal 
  +   * from the tested node.
  +   */
  +  void clearFlags(int which, int flag)
  +  {
  +    IntStack stack=m_stacks[which];
  +    int sz = stack.size();
  +    int pos = (sz - SLOTSPERVALUE)+SLOT_FLAGS;
  +    int flags = stack.elementAt(pos) + 1;
  +    m_stacks[which].setElementAt(flags&(~flag), pos);
  +  }
  +  
  +  /**
  +   * Clear all given flag(s) which are associated with a traversal 
  +   * from the tested node.
  +   */
  +  void clearAllFlags(int flag)
  +  {
  +    for(int i = 0; i < m_stackCount; i++)
  +    {
  +      clearFlags(i, flag);
  +    }
  +  }
  +
  +  /**
  +   * Add the given flag which is associated with a traversal 
  +   * from the tested node.
  +   */
  +  void addFlag(int which, int flag)
  +  {
  +    IntStack stack=m_stacks[which];
  +    int sz = stack.size();
  +    int pos = (sz - SLOTSPERVALUE)+SLOT_FLAGS;
  +    int flags = stack.elementAt(pos) + 1;
  +    m_stacks[which].setElementAt(flags|flag, pos);
  +  }
  +  
  +  /**
  +   * For the given location path stack, add a 
  +   * flag to the bottom of the stack.  This is 
  +   * used for FOLLOWING traversal.
  +   */
  +  void addFlagToBottom(int which, int flag)
  +  {
  +    IntStack stack=m_stacks[which];
  +    int sz = stack.size();
  +    
  +    for(int i = sz; i > 0; i-=SLOTSPERVALUE)
  +    {
  +      int pos = (i - SLOTSPERVALUE)+SLOT_FLAGS;
  +      int flags = stack.elementAt(pos) + 1;
  +      m_stacks[which].setElementAt(flags|flag, pos);
  +    }
  +  }
  +  
  +  /**
  +   * Test the given flag which is associated with a traversal 
  +   * from the tested node.
  +   */
  +  boolean testFlag(int which, int flag)
  +  {
  +    IntStack stack=m_stacks[which];
  +    int sz = stack.size();
  +    int pos = (sz - SLOTSPERVALUE)+SLOT_FLAGS;
  +    int flags = stack.elementAt(pos) + 1;
  +    return (flags & flag) != 0;
  +  }
  +  
  +  /**
  +   * Test the given flag across the stacks which are associated with a traversal 
  +   * from the tested node.
  +   */
  +  boolean testUnionFlags(int flag)
  +  {
  +    for(int i = 0; i < m_stackCount; i++)
  +    {
  +      if(testFlag(i, flag))
  +        return true;
  +    }
  +    return false;
  +  }
  +  
  +  /**
  +   * Test the given flag across the stacks which are associated with a traversal 
  +   * from the tested node.
  +   */
  +  int getUnionFlags(int filter)
  +  {
  +    int stackTopFlagsPos = (size() - SLOTSPERVALUE)+SLOT_FLAGS;
  +    int flags = 0x00000000;
  +    for(int i = 0; i < m_stackCount; i++)
  +    {
  +      IntStack stack=m_stacks[i];      
  +      flags |= stack.elementAt(stackTopFlagsPos) & filter;
  +    }
  +    return flags;
  +  }
  +  
  +  /**
  +   * Test the given flag across the stacks which are associated with a traversal 
  +   * from the tested node.
  +   */
  +  int getUnionFlags()
  +  {
  +    int stackTopFlagsPos = (size() - SLOTSPERVALUE)+SLOT_FLAGS;
  +    int flags = 0x00000000;
  +    int c = m_stackCount;
  +    for(int i = 0; i < c; i++)
  +      flags |= m_stacks[i].m_map[stackTopFlagsPos];      
  +    return flags;
  +  }
   
  +  
     /**
      * Set the index position for a node, associated with 
      * the given LocationPath.
      */
  -  void incrementNodePosition(int which)
  +  void setNodeCount(int which, int nodePos)
     {
  -    m_posStacks[which].setTop(getNodePosition(which)+1);
  +    IntStack stack=m_stacks[which];
  +    int pos = (stack.size() - SLOTSPERVALUE)+SLOT_COUNT;
  +    stack.setElementAt(nodePos, pos);
     }
   
     /**
  -   * Set the index position for a node, associated with 
  +   * Set the found count for a node, associated with 
  +   * the given LocationPath.  The count is copied down 
  +   * the stack 'till the finger (op code position) 
  +   * changes.
  +   */
  +  void incrementNodeCount(int which)
  +  {
  +    IntStack stack=m_stacks[which];
  +    int sz = stack.size();
  +    int pos = (sz - SLOTSPERVALUE)+SLOT_COUNT;
  +    int finger = (sz - SLOTSPERVALUE)+SLOT_FINGER;
  +    int count = stack.elementAt(pos) + 1;
  +    m_stacks[which].setElementAt(count, pos);
  +    for(int i = (sz-SLOTSPERVALUE); i >= SLOTSPERVALUE; i -= SLOTSPERVALUE)
  +    {
  +      int nextfinger = (i - SLOTSPERVALUE)+SLOT_FINGER;
  +      if(nextfinger == finger)
  +        m_stacks[which].setElementAt(count, i);
  +      else
  +        break;
  +    }
  +  }
  +
  +  /**
  +   * Get the index position for a node, associated with 
      * the given LocationPath.
      */
  -  int getNodePosition(int which)
  +  int getNodeCount(int which)
     {
  -    return m_posStacks[which].peek();
  +    if(m_stackCount > 0)
  +    {
  +      IntStack stack=m_stacks[which];
  +      int depth = stack.size();
  +      if(depth > 0)
  +      {
  +        int pos = (depth - SLOTSPERVALUE)+SLOT_COUNT;
  +        int nodePos = stack.elementAt(pos);
  +        return nodePos;
  +      }
  +      else
  +        return 0;
  +    }
  +    else
  +      return 0;
     }
     
     /**
  @@ -209,10 +507,13 @@
      * @param   opCodePos   an opcode position.
      * @return  the <code>opCodePos</code> argument.
      */
  -  public int push(int which, int opCodePos, int nodePos) 
  +  public int push(int which, int opCodePos, int nodePos, int flags) 
     {
  -    m_posStacks[which].push(nodePos);
  -    return m_stacks[which].push(opCodePos);
  +    IntStack stack=m_stacks[which];
  +    int returnVal = stack.push(opCodePos);
  +    stack.push(nodePos);
  +    stack.push(flags);
  +    return returnVal;
     }
   
     /**
  @@ -225,8 +526,11 @@
      */
     public int pop(int which) 
     {
  -    m_posStacks[which].pop();
  -    return m_stacks[which].pop();
  +    IntStack stack=m_stacks[which];
  +    // Could be optimized.
  +    int i = stack.peek();
  +    stack.quickPop(SLOTSPERVALUE);
  +    return i;
     }
  
  /**
      * Pop all stacks by one. 
      *
  @@ -237,7 +541,7 @@
       int n = m_stackCount;
       for(int i = 0; i < n; i++)
       {
  -      pop(i);
  +      m_stacks[i].quickPop(SLOTSPERVALUE);
       }
     }
   
  @@ -251,7 +555,11 @@
      */
     public int peek(int which) 
     {
  -    return m_stacks[which].peek();
  +    IntStack stack=m_stacks[which];
  +    int depth = stack.size();
  +    int pos = (depth - SLOTSPERVALUE)+SLOT_FINGER;
  +    int finger = stack.elementAt(pos);
  +    return finger;
     }
   
     /**
  @@ -281,5 +589,47 @@
           return false;
       }
       return true;
  -  }
  +  }
  
  /**
  +   * Write a diagnostic dump of the stacks to the console.
  +   */
  void writeDiagnostics(int nodeID, java.io.PrintWriter pw)
  +    throws java.io.IOException
  {
  +    int depth = size();
  +    java.text.DecimalFormat formatter 
  +      = (java.text.DecimalFormat)java.text.NumberFormat.getNumberInstance();
  +      formatter.applyPattern("0000");
    
  +    pw.println("************************");
  +    System.out.println("************************");
  +    pw.println("****** NODE# "+formatter.format(nodeID)+" ******");
  +    System.out.println("****** NODE# "+formatter.format(nodeID)+" ******");
  +    pw.println("op  count flags");
    System.out.println("op  count flags");
    int rows=depth/3;
  +    for(int i = (depth-this.SLOTSPERVALUE), l = (rows-1); i >= 0; i-=this.SLOTSPERVALUE, l--)
  +    {
  +      pw.println("------ level "+formatter.format(l)+" ------");
  +      System.out.println("------ level "+formatter.format(l)+" ------");
  +      for(int k = 0; k < m_stackCount; k++)
  +      {
  +        if(0 != k) 
        {
  +          pw.print(" | ");
  +          System.out.print(" | ");
  +        }
        IntStack stack=m_stacks[k];
  +        pw.print(formatter.format(stack.elementAt(i+this.SLOT_FINGER))
  +                            +", "+formatter.format(stack.elementAt(i+this.SLOT_COUNT)));
  +        System.out.print(formatter.format(stack.elementAt(i+this.SLOT_FINGER))
  +                            +", "+formatter.format(stack.elementAt(i+this.SLOT_COUNT)));
  +        int flags = stack.elementAt(i+this.SLOT_FLAGS);
        pw.print(", (");
  +        System.out.print(", (");
  +        pw.print((0 !=(flags & FLAG_SHOULDWALKCHILDREN)) ? "C " : "X ");
  +        System.out.print((0 !=(flags & FLAG_SHOULDWALKCHILDREN)) ? "C " : "X ");
  +        pw.print((0 !=(flags & FLAG_SHOULDWALKATTRIBUTES)) ? "A " : "X ");
  +        System.out.print((0 !=(flags & FLAG_SHOULDWALKATTRIBUTES)) ? "A " : "X ");
  +        pw.print((0 !=(flags & FLAG_SHOULDWALKFOLLOWINGSIBLINGS)) ? "FS" : "X ");
  +        System.out.print((0 !=(flags & FLAG_SHOULDWALKFOLLOWINGSIBLINGS)) ? "FS" : "X ");
  +        boolean shouldWalkAttributes = (0 !=(flags & FLAG_SHOULDWALKATTRIBUTES));
  +        boolean shouldWalkFollowingSiblings = (0 !=(flags & FLAG_SHOULDWALKFOLLOWINGSIBLINGS));
  +        pw.print(")");
  +        System.out.print(")");
        if(k == (m_stackCount-1))
  +        {
          pw.println();
          System.out.println();
        }
  +      }
  +    }
    pw.println("--- #rows    "+formatter.format(rows)+" ---");
    System.out.println("--- #rows    "+formatter.format(rows)+" ---");
    pw.println("--- #columns "+formatter.format(m_stackCount)+" ---");
    System.out.println("--- #columns "+formatter.format(m_stackCount)+" ---");
  +    pw.flush();
  }
   }
  
  
  
  1.5       +12 -2     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.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- XLocator.java	1999/12/13 07:52:10	1.4
  +++ XLocator.java	2000/02/13 16:42:41	1.5
  @@ -92,11 +92,15 @@
      * Execute a union. The union of its operands, which are locationPaths,
      * must be node-sets.
      * @param xpath The xpath that is executing.
  +   * @param execContext The execution context.
      * @param context The current source tree context node.
      * @param opPos The current position in the xpath.m_opMap array.
  +   * @param callback Interface that implements the processLocatedNode method.
  +   * @param callbackInfo Object that will be passed to the processLocatedNode method.
      * @returns the result of the query in an XNodeSet object.
      */
  -  XNodeSet union(XPath xpath, XPathSupport execContext, Node context, int opPos) 
  +  XNodeSet union(XPath xpath, XPathSupport execContext, Node context, 
  +                 int opPos, NodeCallback callback, Object callbackInfo) 
       throws org.xml.sax.SAXException;
   
     /**
  @@ -108,9 +112,15 @@
      * @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 callback Interface that implements the processLocatedNode method.
  +   * @param callbackInfo Object that will be passed to the processLocatedNode method.
  +   * @param stopAtFirst True if only the first found node in doc order is needed.
      * @returns the result of the query in an XNodeSet object.
      */
  -  XNodeSet locationPath(XPath xpath, XPathSupport execContext, Node context, int opPos)
  +  XNodeSet locationPath(XPath xpath, XPathSupport execContext, 
  +                        Node context, int opPos, 
  +                        NodeCallback callback, Object callbackInfo,
  +                        boolean stopAtFirst)
       throws org.xml.sax.SAXException;
     
     /**
  
  
  
  1.15      +320 -248  xml-xalan/src/org/apache/xalan/xpath/XPath.java
  
  Index: XPath.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xpath/XPath.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- XPath.java	2000/02/09 20:11:11	1.14
  +++ XPath.java	2000/02/13 16:42:41	1.15
  @@ -55,7 +55,7 @@
    * <http://www.apache.org/>.
    */
   package org.apache.xalan.xpath;
  -
  + 
   import org.w3c.dom.*;
   import java.util.*;
   import org.apache.xalan.xpath.xml.PrefixResolver;
  @@ -64,7 +64,7 @@
   import org.apache.xalan.xpath.res.XPATHErrorResources;
   import org.apache.xalan.xpath.xml.XSLMessages;
   import org.apache.xalan.xpath.xml.ProblemListener;
  -
  + 
   /** 
    * The XPath class represents the semantic parse tree of the XPath pattern.
    * It is the representation of the grammar which filters out
  @@ -216,7 +216,7 @@
         throw new RuntimeException("In XPath.readObject: "+cnfe.getMessage());
       }
     }
  -
  +  
     /**
      * Given an expression and a context, return the result.
      * @param expression The expression.
  @@ -229,6 +229,27 @@
     public XObject execute(XPathSupport execContext, Node contextNode, 
                           PrefixResolver namespaceContext)
       throws org.xml.sax.SAXException
  +  {
  +    return execute(execContext, contextNode, namespaceContext, null, null, false);
  +  }
  +
  +  /**
  +   * Given an expression and a context, return the result.
  +   * @param execContext The execution context.
  +   * @param contextNode The node that "." expresses.
  +   * @param namespaceContext The context in which namespaces in the 
  +   * queries are supposed to be expanded.
  +   * @param callback Interface that implements the processLocatedNode method.
  +   * @param callbackInfo Object that will be passed to the processLocatedNode method.
  +   * @param stopAtFirst True if the search should stop once the first node in document 
  +   * order is found.
  +   * @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide 
  +   * the error condition is severe enough to halt processing.
  +   */
  +  public XObject execute(XPathSupport execContext, Node contextNode, 
  +                         PrefixResolver namespaceContext, 
  +                         NodeCallback callback, Object callbackInfo, boolean stopAtFirst)
  +    throws org.xml.sax.SAXException
     {    
       PrefixResolver savedPrefixResolver = execContext.getNamespaceContext();
       execContext.setNamespaceContext(namespaceContext);
  @@ -236,7 +257,11 @@
       XObject xobj = null;
       try
       {
  -      xobj = execute(execContext, contextNode, 0);
  +      if(null != callbackInfo)
  +        execContext.pushXPathContext(this, execContext, contextNode, namespaceContext);
  +      xobj = execute(execContext, contextNode, 0, callback, callbackInfo, stopAtFirst);
  +      if(null != callbackInfo)
  +        execContext.popXPathContext();
       }
       finally
       {
  @@ -286,62 +311,32 @@
       
       return score;
     }
  -  
  -  /**
  -   * Get the match score of the given node index.
  -   * @param context The current source tree context node.
  -   * @returns score, one of MATCH_SCORE_NODETEST, 
  -   * MATCH_SCORE_NONE, MATCH_SCORE_OTHER, MATCH_SCORE_QNAME.
  -   */
  -  public double getMatchScore(XPathSupport execContext, org.apache.xalan.xpath.dtm.DTM dtm, int context) 
  -    throws org.xml.sax.SAXException
  -  {
  -    double score = MATCH_SCORE_NONE;
  -    int opPos = 0;
  -    if(m_opMap[opPos] == OP_MATCHPATTERN)
  -    {
  -      opPos = getFirstChildPos(opPos);
  -      
  -      XLocator locator = execContext.getXLocatorFromNode(dtm.getDocument());
  -      
  -      if(null == locator)
  -        locator = execContext.createXLocatorHandler();
  -      
  -      org.apache.xalan.xpath.dtm.DTMNodeLocator dtmLocator 
  -        = (org.apache.xalan.xpath.dtm.DTMNodeLocator)locator;
  -
  -      while(m_opMap[opPos] == OP_LOCATIONPATHPATTERN)
  -      {
  -        int nextOpPos = getNextOpPos(opPos);
  -        
  -        // opPos = getFirstChildPos(opPos);        
  -        score = dtmLocator.locationPathPattern(this, execContext, dtm, context, opPos);
   
  -        if(score != MATCH_SCORE_NONE)
  -          break;
  -        opPos = nextOpPos;
  -      }
  -      
  -    }
  -    else
  -    {
  -      error(dtm.getNode( context ), XPATHErrorResources.ER_EXPECTED_MATCH_PATTERN); //"Expected match pattern in getMatchScore!");
  -    }
       
  -    return score;
  -  }
  -    
     /**
      * Get the position in the current context node list.
      */
  -  int getCountOfContextNodeList(XPathSupport execContext)
  +  int getCountOfContextNodeList(XPath path, XPathSupport execContext, Node context)
  +    throws org.xml.sax.SAXException
     {
  -//    assert(null != m_contextNodeList, "m_contextNodeList must be non-null");
  +    //    assert(null != m_contextNodeList, "m_contextNodeList must be non-null");
       
       if(execContext.getThrowFoundIndex())
         throw new FoundIndex();
       
  -    return execContext.getContextNodeList().getLength();
  +    NodeList cnl = execContext.getContextNodeList();
  +    
  +    if(null == cnl)
  +    {
  +      XObject xobject = execContext.reExecuteXPathContext(path, execContext, context);
  +      if((null != xobject) && (xobject.getType() == XObject.CLASS_NODESET))
  +        cnl = xobject.nodeset();
  +      else if(execContext.getContextNodePosition() > 0)
  +        throw new FoundIndex(); // Tell 'em to try again!
  +      else
  +        return 0; // I give up...
  +    }
  +    return cnl.getLength();
     }
   
     /**
  @@ -353,8 +348,12 @@
       
       if(execContext.getThrowFoundIndex())
         throw new FoundIndex();
  +    
  +    int pos = execContext.getContextNodePosition();
  +    if(pos >= 0)
  +      return pos;
       
  -    int pos = -1;
  +    pos = -1;
   
       if(null != execContext.getContextNodeList())
       {
  @@ -799,9 +798,13 @@
      * 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.
  +   * @param callback Interface that implements the processLocatedNode method.
  +   * @param callbackInfo Object that will be passed to the processLocatedNode method.
      * @returns the union of node-set operands.
      */
  -  protected XNodeSet union(XPathSupport execContext, Node context, int opPos) 
  +  protected XNodeSet union(XPathSupport execContext, 
  +                           Node context, int opPos, 
  +                           NodeCallback callback, Object callbackInfo) 
       throws org.xml.sax.SAXException
     {
       XLocator xlocator = execContext.getXLocatorFromNode(context);
  @@ -809,7 +812,8 @@
       if(null == xlocator)
           xlocator = execContext.createXLocatorHandler();
         
  -    XNodeSet results = xlocator.union(this, execContext, context, opPos);
  +    XNodeSet results = xlocator.union(this, execContext, 
  +                                      context, opPos, callback, callbackInfo);
       
       return results;
     }
  @@ -919,9 +923,14 @@
      * Execute a location path.
      * @param context The current source tree context node.
      * @param opPos The current position in the m_opMap array.
  +   * @param callback Interface that implements the processLocatedNode method.
  +   * @param callbackInfo Object that will be passed to the processLocatedNode method.
      * @returns a node-set.
      */
  -  public XNodeSet locationPath(XPathSupport execContext, Node context, int opPos) 
  +  public XNodeSet locationPath(XPathSupport execContext, 
  +                               Node context, int opPos, 
  +                               NodeCallback callback, Object callbackInfo, 
  +                               boolean stopAtFirst) 
       throws org.xml.sax.SAXException
     {    
       XLocator xlocator = execContext.getXLocatorFromNode(context);
  @@ -929,7 +938,9 @@
       if(null == xlocator)
           xlocator = execContext.createXLocatorHandler();
         
  -    XNodeSet results = xlocator.locationPath(this, execContext, context, opPos);
  +    XNodeSet results = xlocator.locationPath(this, execContext, 
  +                                             context, opPos, callback, callbackInfo, 
  +                                             stopAtFirst);
       
       return results;
     }
  @@ -943,7 +954,7 @@
     public XObject predicate(XPathSupport execContext, Node context, int opPos) 
       throws org.xml.sax.SAXException
     {
  -    XObject expr1 = execute(execContext, context, opPos+2);
  +    XObject expr1 = execute(execContext, context, opPos+2, null, null, true);
       int objType = expr1.getType();
       if((XObject.CLASS_NUMBER != objType) && (XObject.CLASS_BOOLEAN != objType))
       {
  @@ -1026,9 +1037,9 @@
           opPos = getNextOpPos(opPos);
           XNodeSet mnl = null;
           if((opPos < m_opMap[MAPINDEX_LENGTH]) &&
  -           (OP_LOCATIONPATH == m_opMap[opPos]))
  +           (OP_LOCATIONPATH == (m_opMap[opPos] & XPath.LOCATIONPATHEX_MASK)))
           {
  -          mnl = locationPath(execContext, (Node)val, opPos);
  +          mnl = locationPath(execContext, (Node)val, opPos, null, null, false);
           }
           result = (null == mnl) ? new XNodeSet((Node)val)
                                    : mnl;
  @@ -1039,13 +1050,13 @@
           opPos = getNextOpPos(opPos);
           XNodeSet mnl = null;
           if((opPos < m_opMap[MAPINDEX_LENGTH]) &&
  -           (OP_LOCATIONPATH == m_opMap[opPos]))
  +           (OP_LOCATIONPATH == (m_opMap[opPos] & XPath.LOCATIONPATHEX_MASK)))
           {
             NodeList nl = (NodeList)val;
             int nNodes = nl.getLength();
             for(int i = 0; i < nNodes; i++)
             {
  -            XNodeSet xnl = locationPath(execContext, nl.item(i), opPos);
  +            XNodeSet xnl = locationPath(execContext, nl.item(i), opPos, null, null, false);
               if(null == xnl)
                 mnl = xnl;
               else
  @@ -1212,202 +1223,235 @@
       }
       return targetStrings;
     }
  +  
  +  /**
  +   * Execute the XPath object.
  +   * @param execContext The execution context.
  +   * @param context The current source tree context node.
  +   * @param opPos The current position in the xpath.m_opMap array.
  +   * @param callback Interface that implements the processLocatedNode method.
  +   * @param callbackInfo Object that will be passed to the processLocatedNode method.
  +   * @return The result of the XPath.
  +   */
  +  public XObject execute(XPathSupport execContext, 
  +                         Node context, int opPos)
  +    throws org.xml.sax.SAXException
  +  {
  +    return execute(execContext, context, opPos, null, null, false);
  +  }
   
  -  public XObject execute(XPathSupport execContext, Node context, int opPos)
  +  /**
  +   * Execute the XPath object.
  +   * @param execContext The execution context.
  +   * @param context The current source tree context node.
  +   * @param opPos The current position in the xpath.m_opMap array.
  +   * @param callback Interface that implements the processLocatedNode method.
  +   * @param callbackInfo Object that will be passed to the processLocatedNode method.
  +   * @return The result of the XPath.
  +   */
  +  public XObject execute(XPathSupport execContext, 
  +                         Node context, int opPos, 
  +                         NodeCallback callback, Object callbackInfo, boolean stopAtFirst)
       throws org.xml.sax.SAXException
     {
       XObject result = null;
  -    switch(m_opMap[opPos])
  +    boolean doLoop = true;
  +    while(doLoop)
       {
  -    case OP_XPATH:
  -      result = execute(execContext, context, opPos+2);
  -      break;
  -    case OP_MATCHPATTERN:
  -      result = matchPattern(execContext, context, opPos+2);
  -      break;
  -    case EMPTY:
  -      opPos++;
  -      break;
  -    case OP_OR:
  -      result = or(execContext, context, opPos);
  -      break;
  -    case OP_AND:
  -      result = and(execContext, context, opPos);
  -      break;
  -    case OP_NOTEQUALS:
  -      result = notequals(execContext, context, opPos);
  -      break;
  -    case OP_EQUALS:
  -      result = equals(execContext, context, opPos);
  -      break;
  -    case OP_LTE:
  -      result = lte(execContext, context, opPos);
  -      break;
  -    case OP_LT:
  -      result = lt(execContext, context, opPos);
  -      break;
  -    case OP_GTE:
  -      result = gte(execContext, context, opPos);
  -      break;
  -    case OP_GT:
  -      result = gt(execContext, context, opPos);
  -      break;
  -    case OP_PLUS:
  -      result = plus(execContext, context, opPos);
  -      break;
  -    case OP_MINUS:
  -      result = minus(execContext, context, opPos);
  -      break;
  -    case OP_MULT:
  -      result = mult(execContext, context, opPos);
  -      break;
  -    case OP_DIV:
  -      result = div(execContext, context, opPos);
  -      break;
  -    case OP_MOD:
  -      result = mod(execContext, context, opPos);
  -      break;
  -    case OP_QUO:
  -      result = quo(execContext, context, opPos);
  -      break;
  -    case OP_NEG:
  -      result = neg(execContext, context, opPos);
  -      break;
  -    case OP_STRING:
  -      result = string(execContext, context, opPos);
  -      break;
  -    case OP_BOOL:
  -      result = bool(execContext, context, opPos);
  -      break;
  -    case OP_NUMBER:
  -      result = number(execContext, context, opPos);
  -      break;
  -    case OP_UNION:
  -      result = union(execContext, context, opPos);
  -      break;
  -    case OP_LITERAL:
  -      result = literal(execContext, context, opPos);
  -      break;
  -    case OP_VARIABLE:
  -      result = variable(execContext, context, opPos);
  -      break;
  -    case OP_GROUP:
  -      result = group(execContext, context, opPos);
  -      break;
  -    case OP_NUMBERLIT:
  -      result = numberlit(execContext, context, opPos);
  -      break;
  -    case OP_ARGUMENT:
  -      result = arg(execContext, context, opPos);
  -      break;
  -    case OP_EXTFUNCTION:
  -      {
  -        int endExtFunc = opPos+m_opMap[opPos+1]-1;
  -        opPos = getFirstChildPos(opPos);
  -        String ns = (String)m_tokenQueue[m_opMap[opPos]];
  -        opPos++;
  -        String funcName = (String)m_tokenQueue[m_opMap[opPos]];
  -        opPos++;
  -        Vector args = new Vector();
  -        while(opPos < endExtFunc)
  -        {
  -          int nextOpPos = getNextOpPos(opPos);
  -          args.addElement( execute(execContext, context, opPos) );
  -          opPos = nextOpPos;
  -        }
  -        result = extfunction(execContext, context, opPos, ns, funcName, args);
  -      }
  -      break;
  -    case OP_FUNCTION:
  +      switch(m_opMap[opPos])
         {
  -        int endFunc = opPos+m_opMap[opPos+1]-1;
  -        opPos = getFirstChildPos(opPos);
  -        int funcID = m_opMap[opPos];
  -        opPos++;
  -        Vector args = new Vector();
  -        while(opPos < endFunc)
  -        {
  -          int nextOpPos = getNextOpPos(opPos);
  -          args.addElement(execute(execContext, context, opPos));
  -          opPos = nextOpPos;
  -        }
  -        if(-1 != funcID)
  -        {
  -        result = function(execContext, context, opPos, funcID, args);
  -        }
  -        else
  -        {
  -          warn(XPATHErrorResources.WG_FUNCTION_TOKEN_NOT_FOUND); //"function token not found.");
  -        }
  +      case OP_XPATH:
  +        opPos+=2;
  +        continue;
  +      case OP_MATCHPATTERN:
  +          result = matchPattern(execContext, context, opPos+2);
  +          break;
  +      case EMPTY:
  +          opPos++;
  +          break;
  +      case OP_OR:
  +          result = or(execContext, context, opPos);
  +          break;
  +      case OP_AND:
  +          result = and(execContext, context, opPos);
  +          break;
  +      case OP_NOTEQUALS:
  +          result = notequals(execContext, context, opPos);
  +          break;
  +      case OP_EQUALS:
  +          result = equals(execContext, context, opPos);
  +          break;
  +      case OP_LTE:
  +          result = lte(execContext, context, opPos);
  +          break;
  +      case OP_LT:
  +          result = lt(execContext, context, opPos);
  +          break;
  +      case OP_GTE:
  +          result = gte(execContext, context, opPos);
  +          break;
  +      case OP_GT:
  +          result = gt(execContext, context, opPos);
  +          break;
  +      case OP_PLUS:
  +          result = plus(execContext, context, opPos);
  +          break;
  +      case OP_MINUS:
  +          result = minus(execContext, context, opPos);
  +          break;
  +      case OP_MULT:
  +          result = mult(execContext, context, opPos);
  +          break;
  +      case OP_DIV:
  +          result = div(execContext, context, opPos);
  +          break;
  +      case OP_MOD:
  +          result = mod(execContext, context, opPos);
  +          break;
  +      case OP_QUO:
  +          result = quo(execContext, context, opPos);
  +          break;
  +      case OP_NEG:
  +          result = neg(execContext, context, opPos);
  +          break;
  +      case OP_STRING:
  +          result = string(execContext, context, opPos);
  +          break;
  +      case OP_BOOL:
  +          result = bool(execContext, context, opPos);
  +          break;
  +      case OP_NUMBER:
  +          result = number(execContext, context, opPos);
  +          break;
  +      case OP_UNION:
  +          result = union(execContext, context, opPos, callback, callbackInfo);
  +          break;
  +      case OP_LITERAL:
  +          result = literal(execContext, context, opPos);
  +          break;
  +      case OP_VARIABLE:
  +          result = variable(execContext, context, opPos);
  +          break;
  +      case OP_GROUP:
  +          result = group(execContext, context, opPos);
  +          break;
  +      case OP_NUMBERLIT:
  +          result = numberlit(execContext, context, opPos);
  +          break;
  +      case OP_ARGUMENT:
  +          result = arg(execContext, context, opPos);
  +          break;
  +      case OP_EXTFUNCTION:
  +          {
  +            int endExtFunc = opPos+m_opMap[opPos+1]-1;
  +            opPos = getFirstChildPos(opPos);
  +            String ns = (String)m_tokenQueue[m_opMap[opPos]];
  +            opPos++;
  +            String funcName = (String)m_tokenQueue[m_opMap[opPos]];
  +            opPos++;
  +            Vector args = new Vector();
  +            while(opPos < endExtFunc)
  +            {
  +              int nextOpPos = getNextOpPos(opPos);
  +              args.addElement( execute(execContext, context, opPos) );
  +              opPos = nextOpPos;
  +            }
  +            result = extfunction(execContext, context, opPos, ns, funcName, args);
  +          }
  +          break;
  +      case OP_FUNCTION:
  +          {
  +            int endFunc = opPos+m_opMap[opPos+1]-1;
  +            opPos = getFirstChildPos(opPos);
  +            int funcID = m_opMap[opPos];
  +            opPos++;
  +            Vector args = new Vector();
  +            while(opPos < endFunc)
  +            {
  +              int nextOpPos = getNextOpPos(opPos);
  +              args.addElement(execute(execContext, context, opPos));
  +              opPos = nextOpPos;
  +            }
  +            if(-1 != funcID)
  +            {
  +              result = function(execContext, context, opPos, funcID, args);
  +            }
  +            else
  +            {
  +              warn(XPATHErrorResources.WG_FUNCTION_TOKEN_NOT_FOUND); //"function token not found.");
  +            }
  +          }
  +          break;
  +      case OP_LOCATIONPATH_EX:
  +      case OP_LOCATIONPATH:
  +          result = locationPath(execContext, context, opPos, callback, callbackInfo, stopAtFirst);
  +          break;
  +      case OP_LOCATIONPATHPATTERN:
  +          result = locationPathPattern(execContext, context, opPos);
  +          break;
  +          /*
  +          case OP_PREDICATE:
  +          break;
  +          case FROM_ANCESTORS:
  +          break;
  +          case FROM_ANCESTORS_OR_SELF:
  +          break;
  +          case FROM_ATTRIBUTES:
  +          break;
  +          case FROM_CHILDREN:
  +          break;
  +          case FROM_DESCENDANTS:
  +          break;
  +          case FROM_DESCENDANTS_OR_SELF:
  +          break;
  +          case FROM_FOLLOWING:
  +          break;
  +          case FROM_FOLLOWING_SIBLINGS:
  +          break;
  +          case FROM_PARENT:
  +          break;
  +          case FROM_PRECEDING:
  +          break;
  +          case FROM_PRECEDING_SIBLINGS:
  +          break;
  +          case FROM_SELF:
  +          break;
  +          case FROM_NAMESPACE:
  +          break;
  +          // case FROM_ATTRIBUTE:
  +          //  break;
  +          // case FROM_DOC:
  +          //  break;
  +          // case FROM_DOCREF:
  +          //  break;
  +          // case FROM_ID:
  +          //   break;
  +          // case FROM_IDREF:
  +          //  break;
  +          case FROM_ROOT:
  +          break;
  +          case NODETYPE_COMMENT:
  +          break;
  +          case NODETYPE_TEXT:
  +          break;
  +          case NODETYPE_PI:
  +          break;
  +          case NODETYPE_NODE:
  +          break;
  +          case NODETYPE_ROOT:
  +          break;
  +          case NODETYPE_ANYELEMENT:
  +          break;
  +          case NODENAME:
  +          break;
  +          */
  +      default:
  +          error(context, XPATHErrorResources.ER_UNKNOWN_OPCODE, new Object[] {Integer.toString(m_opMap[opPos])}); //"ERROR! Unknown op code: "+m_opMap[opPos]);
         }
  -      break;
  -    case OP_LOCATIONPATH:
  -      result = locationPath(execContext, context, opPos);
  -      break;
  -    case OP_LOCATIONPATHPATTERN:
  -      result = locationPathPattern(execContext, context, opPos);
  -      break;
  -      /*
  -    case OP_PREDICATE:
  -      break;
  -    case FROM_ANCESTORS:
  -      break;
  -    case FROM_ANCESTORS_OR_SELF:
  -      break;
  -    case FROM_ATTRIBUTES:
  -      break;
  -    case FROM_CHILDREN:
  -      break;
  -    case FROM_DESCENDANTS:
  -      break;
  -    case FROM_DESCENDANTS_OR_SELF:
  -      break;
  -    case FROM_FOLLOWING:
  -      break;
  -    case FROM_FOLLOWING_SIBLINGS:
  -      break;
  -    case FROM_PARENT:
  -      break;
  -    case FROM_PRECEDING:
  -      break;
  -    case FROM_PRECEDING_SIBLINGS:
  -      break;
  -    case FROM_SELF:
  -      break;
  -    case FROM_NAMESPACE:
  -      break;
  -    // case FROM_ATTRIBUTE:
  -    //  break;
  -    // case FROM_DOC:
  -    //  break;
  -    // case FROM_DOCREF:
  -    //  break;
  -    // case FROM_ID:
  -    //   break;
  -    // case FROM_IDREF:
  -    //  break;
  -    case FROM_ROOT:
  -      break;
  -    case NODETYPE_COMMENT:
  -      break;
  -    case NODETYPE_TEXT:
  -      break;
  -    case NODETYPE_PI:
  -      break;
  -    case NODETYPE_NODE:
  -      break;
  -    case NODETYPE_ROOT:
  -      break;
  -    case NODETYPE_ANYELEMENT:
  -      break;
  -    case NODENAME:
  -      break;
  -      */
  -    default:
  -      error(context, XPATHErrorResources.ER_UNKNOWN_OPCODE, new Object[] {Integer.toString(m_opMap[opPos])}); //"ERROR! Unknown op code: "+m_opMap[opPos]);
  -    }
  -    return result;
  +    doLoop = false;
     }
  +  return result;
  +}
     
     // ============= Op Code Position Helper Functions =================
     private void ____OPCODE_POSITION_HELPER_FUNCTIONS____(){}
  @@ -1941,6 +1985,9 @@
      *  XNodeSet
      */
     public static final int OP_LOCATIONPATH = 28;
  +  public static final int LOCATIONPATHEX_MASK = 0xFFFF0000;
  +  public static final int LOCATIONPATHEX_ISSIMPLE = 0x00010000;
  +  public static final int OP_LOCATIONPATH_EX = (28 | 0x00010000);
       
   
     /**
  @@ -2248,5 +2295,30 @@
      * The number of elements that m_patternMap maps;
      */
     public int m_patternMapSize;
  +  
  +  //====================
  +  /*
  +  public static void main( String argv[] )
  +  {
  +    TransformFactory sfactory = XSLTFactory.newTransformFactory(...);
  +    Params params = new Params();  // Bag of params..
  +    params.set("foo", "http://foo.com", "hello");
  +
  +    Transform transform1 = sfactory .newTransform(new InputSource("t1.xsl"));
  +    XSLTProcessor processor1 = transform1.newProcessor();
  +
  +    Transform transform2= sfactory.newTransform(new InputSource("t2.xsl"));
  +    XSLTProcessor processor2 = transform2.newProcessor();
  +
  +    Transform  transform3 = sfactory.newTransform(new InputSource("t3.xsl"));
  +    XSLTProcessor processor3= transform3 .newProcessor();
  +
  +    processor3.setResultTarget(new Result(System.out));
  +    processor2.setResultTarget(new Result(processor3));
  +    processor1.process(new InputSource("foo.xml"), params, new Result(processor2));
  +  }
  +  */
  +//====================
  +
      
   }
  
  
  
  1.17      +80 -1     xml-xalan/src/org/apache/xalan/xpath/XPathProcessorImpl.java
  
  Index: XPathProcessorImpl.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xpath/XPathProcessorImpl.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- XPathProcessorImpl.java	2000/02/09 20:11:11	1.16
  +++ XPathProcessorImpl.java	2000/02/13 16:42:41	1.17
  @@ -187,8 +187,16 @@
         }
         error(XPATHErrorResources.ER_EXTRA_ILLEGAL_TOKENS, new Object[] {extraTokens}); //"Extra illegal tokens: "+extraTokens);
       }
  -
  +    pathObj.shrink();
  +    doStaticAnalysis(pathObj);
     }
  +  
  +  /**
  +   * Analyze the XPath object to give optimization information.
  +   */
  +  void doStaticAnalysis(XPath pathObj)
  +  {
  +  }
    
     /**
      * Given an string, make an XPath object, on order that a parse doesn't 
  @@ -219,6 +227,7 @@
       // Terminate for safety.
       m_xpath.m_opMap[m_xpath.m_opMap[m_xpath.MAPINDEX_LENGTH]] = m_xpath.ENDOP;
       m_xpath.m_opMap[m_xpath.MAPINDEX_LENGTH] += 1;
  +    m_xpath.shrink();
      }
   
     // Lexical Analysis
  @@ -1747,7 +1756,60 @@
         while(continueOrLoop);
       m_xpath.m_opMap[opPos + m_xpath.MAPINDEX_LENGTH] = m_xpath.m_opMap[m_xpath.MAPINDEX_LENGTH] - opPos;
     }
  +  
  +  /**
  +   * Analyze a union pattern and tell if the axes are 
  +   * all descendants.
  +   * (Move to XPath?)
  +   */
  +  static boolean isLocationPathSimpleFollowing(XPath xpath, int opPos)
  +  {
  +    int posOfLastOp = xpath.getNextOpPos(opPos)-1;
  +    
  +    opPos = xpath.getFirstChildPos(opPos);
  +    // step
  +    int stepType = xpath.m_opMap[opPos];
  +    
  +    // make sure all step types are going forwards
  +    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:
  +    case XPath.FROM_FOLLOWING_SIBLINGS:
  +      if(xpath.m_opMap[xpath.getNextOpPos(opPos)] == xpath.ENDOP)
  +      {
  +        // Add the length of the step itself, plus the length of the op, 
  +        // and two length arguments, to the op position.
  +        opPos = (xpath.getArgLengthOfStep(opPos)+xpath.getFirstChildPosOfStep(opPos));
  +        int nextStepType = xpath.m_opMap[opPos];
  +                
  +        if(xpath.OP_PREDICATE == nextStepType)
  +        {
  +          int firstPredPos = opPos+2;
  +          int predicateType = xpath.m_opMap[firstPredPos];
  +          if((XPath.OP_NUMBERLIT == predicateType) || (XPath.OP_NUMBER == predicateType)
  +             || (XPath.FUNC_NUMBER == predicateType))
  +          {
  +            return false;
  +          }
  +          opPos = xpath.getNextOpPos(opPos);
  +          nextStepType = xpath.m_opMap[opPos];
  +          // Multiple predicates?
  +          if(xpath.OP_PREDICATE == nextStepType)
  +            return false;
  +        }
  +        return true;
  +      }
  +      break;
  +    }
  +    return false;
  +  }
   
  +
     /**
      * 
      * --------------------------------------------------------------------------------
  @@ -1770,6 +1832,7 @@
       if(tokenIs('/'))
       {
         nextToken();
  +      int locationPathOpPos = opPos;
         insertOp(opPos, 2, m_xpath.OP_LOCATIONPATH);
         RelativeLocationPath();
   
  @@ -1778,6 +1841,10 @@
         m_xpath.m_opMap[m_xpath.MAPINDEX_LENGTH] += 1;
   
         m_xpath.m_opMap[opPos + m_xpath.MAPINDEX_LENGTH] = m_xpath.m_opMap[m_xpath.MAPINDEX_LENGTH] - opPos;
  +      if(isLocationPathSimpleFollowing(m_xpath, locationPathOpPos))
  +      {
  +        m_xpath.m_opMap[locationPathOpPos] = XPath.OP_LOCATIONPATH_EX;
  +      }
       }
     }
   
  @@ -1799,6 +1866,7 @@
       
       if(tokenIs('['))
       {
  +      int locationPathOpPos = opPos;
         insertOp(opPos, 2, m_xpath.OP_LOCATIONPATH);
         
         while(tokenIs('['))
  @@ -1817,6 +1885,10 @@
         m_xpath.m_opMap[m_xpath.MAPINDEX_LENGTH] += 1;
   
         m_xpath.m_opMap[opPos + m_xpath.MAPINDEX_LENGTH] = m_xpath.m_opMap[m_xpath.MAPINDEX_LENGTH] - opPos;
  +      if(isLocationPathSimpleFollowing(m_xpath, locationPathOpPos))
  +      {
  +        m_xpath.m_opMap[locationPathOpPos] = XPath.OP_LOCATIONPATH_EX;
  +      }
       }
   
       /*
  @@ -1974,6 +2046,7 @@
       throws org.xml.sax.SAXException
     {
       int opPos = m_xpath.m_opMap[m_xpath.MAPINDEX_LENGTH];
  +    int locationPathOpPos = opPos;
       appendOp(2, m_xpath.OP_LOCATIONPATH);
       
       if(tokenIs('/'))
  @@ -1994,6 +2067,10 @@
       m_xpath.m_opMap[m_xpath.MAPINDEX_LENGTH] += 1;
       
       m_xpath.m_opMap[opPos + m_xpath.MAPINDEX_LENGTH] = m_xpath.m_opMap[m_xpath.MAPINDEX_LENGTH] - opPos;
  +    if(isLocationPathSimpleFollowing(m_xpath, locationPathOpPos))
  +    { 
  +      m_xpath.m_opMap[locationPathOpPos] = XPath.OP_LOCATIONPATH_EX;
  +    }
     }
     
     /**
  @@ -2769,6 +2846,7 @@
         }
         break;
       case XPath.OP_LOCATIONPATH:
  +    case XPath.OP_LOCATIONPATH_EX:
         System.out.println("OP_LOCATIONPATH"+" {");
         int endPath = opPos+xpath.m_opMap[opPos+1]-1;
         opPos+=2;
  @@ -3204,6 +3282,7 @@
           opPos++;
         }
         break;
  +    case XPath.OP_LOCATIONPATH_EX:
       case XPath.OP_LOCATIONPATH:
         diagnoseOp2("OP_LOCATIONPATH", xpath, opPos);
         int endPath = opPos+xpath.m_opMap[opPos+1]-1;
  
  
  
  1.7       +56 -27    xml-xalan/src/org/apache/xalan/xpath/XPathSupport.java
  
  Index: XPathSupport.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xpath/XPathSupport.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- XPathSupport.java	1999/12/16 06:10:44	1.6
  +++ XPathSupport.java	2000/02/13 16:42:41	1.7
  @@ -72,9 +72,39 @@
     /**
      * Set the current context node list.
      */
  -  void setContextNodeList(NodeList nl);
  +  public void pushContextNodeList(NodeList nl);
     
     /**
  +   * Pop the current context node list.
  +   */
  +  public void popContextNodeList();
  +  
  +  /**
  +   * Get the current context node list.
  +   */
  +  int getContextNodePosition();
  +  
  +  /**
  +   * Increment the current context node position.
  +   */
  +  void incrementContextNodePosition(Node node);
  +  
  +  /**
  +   * Decrement the current context node position.
  +   */
  +  void decrementContextNodePosition();
  +
  +  /**
  +   * Get the current context node list.
  +   */
  +  void pushContextNodePosition();
  +
  +  /**
  +   * Get the current context node list.
  +   */
  +  void popContextNodePosition();
  +
  +  /**
      * Get the current context node.
      */
     Node getCurrentNode();
  @@ -85,6 +115,30 @@
     void setCurrentNode(Node n);
     
     /**
  +   * Push the current XPath selection, 
  +   * needed for support of the last() function.  Ugh.
  +   */
  +  void pushXPathContext(XPath xpath, XPathSupport execContext, Node contextNode, 
  +                         PrefixResolver namespaceContext);
  +  
  +  /**
  +   * Pop the current XPathContext.
  +   */
  +  void popXPathContext();
  +
  +  /**
  +   * Reexecute the last xpath context after the specified one.
  +   */
  +  XObject reExecuteXPathContext(XPath path, XPathSupport execContext, Node context)
  +    throws SAXException;
  +  
  +  /**
  +   * Push a dummy XPathContext so we can tell that the top-level xpath isn't 
  +   * in effect.
  +   */
  +  public void pushDummyXPathContext();
  +  
  +  /**
      * Get the current namespace context for the xpath.
      */
     PrefixResolver getNamespaceContext();
  @@ -183,32 +237,7 @@
      */
     public void addExtensionNamespace (String uri,
            ExtensionFunctionHandler extNS);
  -  
  -  /**
  -   * Set a callback that may be called by XPath as nodes are located.
  -   * The callback will only be called if the XLocator determines that 
  -   * the location path can process the nodes in document order.
  -   * If the callback is called, the nodes will not be put into the 
  -   * node list, and the LocationPath will return an empty node list.
  -   * The callback will be set to null after the given LocationPath or 
  -   * Union is processed.
  -   * @param callback Interface that implements the processLocatedNode method.
  -   * @param callbackInfo Object that will be passed to the processLocatedNode method.
  -   */
  -  public void setCallback(NodeCallback callback, Object callbackInfo);
  -  
  -  /**
  -   * Get the callback that may be called by XPath as nodes are located.
  -   * @return the current callback method.
  -   */
  -  public NodeCallback getCallback();
  -
  -  /**
  -   * Get the object that will be passed to the processLocatedNode method.
  -   * @return object that will be passed to the processLocatedNode method.
  -   */
  -  public Object getCallbackInfo();
  -  
  +    
     /**
      * ThrowFoundIndex tells if FoundIndex should be thrown 
      * if index is found.
  
  
  
  1.9       +204 -23   xml-xalan/src/org/apache/xalan/xpath/XPathSupportDefault.java
  
  Index: XPathSupportDefault.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xpath/XPathSupportDefault.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- XPathSupportDefault.java	2000/01/31 08:31:14	1.8
  +++ XPathSupportDefault.java	2000/02/13 16:42:41	1.9
  @@ -63,14 +63,216 @@
   import java.net.URL;
   import org.xml.sax.SAXException;
   import org.xml.sax.DocumentHandler;
  +import org.apache.xalan.xpath.xml.IntStack;
   
   /**
  - * Dummy class in order to make the XPath object happy 
  - * for diagnostic purposes.
  + * Default class for execution context when XPath is used by itself.
    */
   public class XPathSupportDefault implements XPathSupport
   {
     /**
  +   * Keep stack of positions within the current context list.
  +   */
  +  private IntStack m_contextCounts = new IntStack();
  +  
  +  /**
  +   * The current context node list.
  +   */
  +  private Stack m_contextNodeLists = new Stack();
  +
  +  /**
  +   * The current xpath state.  Note... it would be 
  +   * a good optimization to make our own class and 
  +   * pre-allocate the XPathContext objects.
  +   */
  +  private Stack m_xpathContextStates = new Stack();
  +  
  +  /**
  +   * Class to stort the state of the XPath for re-execution.
  +   */
  +  class XPathContext
  +  {
  +    XPath xpath;
  +    XPathSupport execContext;
  +    Node contextNode;
  +    PrefixResolver namespaceContext;
  +    int contextNodePosition;
  +    NodeList contextNodeList;
  +    XObject result = null;
  +                                                              
  +    XPathContext(XPath xpath, XPathSupport execContext, Node contextNode, 
  +                         PrefixResolver namespaceContext)
  +    {
  +      this.xpath = xpath;
  +      this.execContext = execContext;
  +      this.namespaceContext = namespaceContext;
  +      this.contextNode = contextNode;
  +      if(m_contextCounts.empty())
  +      {
  +        contextNodePosition = -200;
  +        contextNodeList = null;
  +      }
  +      else
  +      {
  +        contextNodePosition = getContextNodePosition();
  +        contextNodeList = getContextNodeList();
  +      }
  +    }
  +    
  +    XObject execute()
  +      throws SAXException
  +    {
  +      if(null != result)
  +        return result;
  +      
  +      m_contextNodeLists.push(contextNodeList);
  +      m_contextCounts.push(contextNodePosition);
  +      try
  +      {
  +        result = xpath.execute(execContext, contextNode, 
  +                              namespaceContext);
  +      }
  +      finally
  +      {
  +        m_contextNodeLists.pop();
  +        m_contextCounts.pop();
  +      }
  +      return result;
  +      
  +    }
  +    
  +  }
  +  
  +  private XPathContext m_dummyXPathContext = new XPathContext(null, null, null, null);
  +
  +  /**
  +   * Push the current XPath selection, 
  +   * needed for support of the last() function.  Ugh.
  +   */
  +  public void pushXPathContext(XPath xpath, XPathSupport execContext, Node contextNode, 
  +                         PrefixResolver namespaceContext)
  +  {
  +    XPathContext xpathContext 
  +      = new XPathContext(xpath, execContext, contextNode, 
  +                         namespaceContext);
  +    m_xpathContextStates.push(xpathContext);
  +  }
  +  
  +  /**
  +   * Pop the current XPathContext.
  +   */
  +  public void popXPathContext()
  +  {
  +    m_xpathContextStates.pop();
  +  }
  +  
  +  /**
  +   * Push a dummy XPathContext so we can tell that the top-level xpath isn't 
  +   * in effect.
  +   */
  +  public void pushDummyXPathContext()
  +  {
  +    m_xpathContextStates.push(m_dummyXPathContext);
  +  }
  +
  +  
  +  /**
  +   * Reexecute the xpath context below the specified one.
  +   */
  +  public XObject reExecuteXPathContext(XPath path, XPathSupport execContext, Node context)
  +    throws SAXException
  +  {
  +    int size = m_xpathContextStates.size();
  +    for(int i = (size-1); i >= 0; i--)
  +    {
  +      XPathContext xpathContext = (XPathContext)m_xpathContextStates.elementAt(i);
  +      if(null == xpathContext.xpath)
  +        return null;
  +      
  +      if((xpathContext.contextNode == context) 
  +         && (xpathContext.xpath == path)
  +         && (xpathContext.execContext == context))
  +        continue;
  +      
  +      return xpathContext.execute();
  +    }
  +    
  +    return null;
  +  }
  +  
  +  /**
  +   * Get the current context node list.
  +   */
  +  public int getContextNodePosition()
  +  {
  +    if(!m_contextCounts.empty())
  +      return m_contextCounts.peek();
  +    else
  +      return -200;
  +  }
  +  
  +  /**
  +   * Increment the current context node position.
  +   */
  +  public void incrementContextNodePosition(Node node)
  +  {
  +    int newNodePos = getContextNodePosition()+1;
  +    m_contextCounts.setTop(newNodePos);
  +  }
  + 
  +  /**
  +   * Decrement the current context node position.
  +   */
  +  public void decrementContextNodePosition()
  +  {
  +    m_contextCounts.setTop(getContextNodePosition()-1);
  +  }
  +
  +  /**
  +   * Get the current context node list.
  +   */
  +  public void pushContextNodePosition()
  +  {
  +    m_contextNodeLists.push(null);
  +    m_contextCounts.push(0);
  +  }
  +
  +  /**
  +   * Get the current context node list.
  +   */
  +  public void popContextNodePosition()
  +  {
  +    m_contextNodeLists.pop();
  +    m_contextCounts.pop();
  +  }
  +  
  +  /**
  +   * Get the current context node list.
  +   */
  +  public NodeList getContextNodeList()
  +  {
  +    return (NodeList)m_contextNodeLists.peek();
  +  }
  +  
  +  /**
  +   * Set the current context node list.
  +   */
  +  public void pushContextNodeList(NodeList nl)
  +  {
  +    m_contextCounts.push(-200);
  +    m_contextNodeLists.push(nl);
  +  }
  +
  +  /**
  +   * Pop the current context node list.
  +   */
  +  public void popContextNodeList()
  +  {
  +    m_contextCounts.pop();
  +    m_contextNodeLists.pop();
  +  }
  +
  +  /**
      * Tells if FoundIndex should be thrown if index is found.
      * This is an optimization for match patterns.
      */
  @@ -97,11 +299,6 @@
     {
       m_throwFoundIndex = b;
     }
  -
  -  /**
  -   * The current context node.
  -   */
  -  private NodeList m_contextNodeList = null;
     
     /**
      * The current node.
  @@ -114,22 +311,6 @@
      * (Is this really needed?)
      */
     private PrefixResolver m_currentPrefixResolver = null;
  -  
  -  /**
  -   * Get the current context node list.
  -   */
  -  public NodeList getContextNodeList()
  -  {
  -    return m_contextNodeList;
  -  }
  -  
  -  /**
  -   * Set the current context node list.
  -   */
  -  public void setContextNodeList(NodeList nl)
  -  {
  -    m_contextNodeList = nl;
  -  }
     
     /**
      * Get the current context node.
  
  
  
  1.1                  xml-xalan/src/org/apache/xalan/xpath/EmptyNodeListImpl.java
  
  Index: EmptyNodeListImpl.java
  ===================================================================
  package org.apache.xalan.xpath;
  
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  
  /**
   * Class to protect a MutableNodeListImpl from being written to.  Really a 
   * debugging class.
   */
  class EmptyNodeListImpl extends MutableNodeListImpl
  {
    EmptyNodeListImpl()
    {
    }
    
    public void addNode(Node n)
    {
      // checkDups(n);
      throw new RuntimeException("Programmer's error: EmptyNodeListImpl can not be written to.");
    }
  
    /**
     * Insert a node at a given position.
     */
    public void insertNode(Node n, int pos)
    {
      // checkDups(n);
      throw new RuntimeException("Programmer's error: EmptyNodeListImpl can not be written to.");
    }
  
  
    /**
     * Remove a node.
     */
    public void removeNode(Node n)
    {
      throw new RuntimeException("Programmer's error: EmptyNodeListImpl can not be written to.");
    }
  
    /**
     * Set a item to null, so the list doesn't
     * have to keep being compressed.
     */
    public void setItemNull(int pos)
    {
      throw new RuntimeException("Programmer's error: EmptyNodeListImpl can not be written to.");
    }
    
    /**
     * Copy NodeList members into this nodelist, adding in 
     * document order.  If a node is null, don't add it.
     */
    public void addNodes(NodeList nodelist)
    {
      throw new RuntimeException("Programmer's error: EmptyNodeListImpl can not be written to.");
    }
  
    /**
     * Copy NodeList members into this nodelist, adding in 
     * document order.  If a node is null, don't add it.
     */
    public void addNodesInDocOrder(NodeList nodelist, XPathSupport support)
    {
      throw new RuntimeException("Programmer's error: EmptyNodeListImpl can not be written to.");
    }
    
    /**
     * Add the node into a vector of nodes where it should occur in 
     * document order.
     * @param v Vector of nodes, presumably containing Nodes
     * @param obj Node object.
     * @param test true if we should test for doc order
     * @return insertIndex.
     */
    public int addNodeInDocOrder(Node node, boolean test, XPathSupport support)
    {
      throw new RuntimeException("Programmer's error: EmptyNodeListImpl can not be written to.");
  
    } // end addNodeInDocOrder(Vector v, Object obj)
  
    /**
     * Add the node into a vector of nodes where it should occur in 
     * document order.
     * @param v Vector of nodes, presumably containing Nodes
     * @param obj Node object.
     */
    public int addNodeInDocOrder(Node node, XPathSupport support)
    {
      throw new RuntimeException("Programmer's error: EmptyNodeListImpl can not be written to.");
    } // end addNodeInDocOrder(Vector v, Object obj)
  }
  
  
  
  1.2       +10 -3     xml-xalan/src/org/apache/xalan/xpath/xml/IntStack.java
  
  Index: IntStack.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xpath/xml/IntStack.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- IntStack.java	1999/12/13 07:40:11	1.1
  +++ IntStack.java	2000/02/13 16:42:43	1.2
  @@ -108,8 +108,17 @@
       removeElementAt(len - 1);
   
       return i;
  +  }
  
  /**
  +   * Quickly pops a number of items from the stack. 
  +   *
  +   * @exception  EmptyStackException  if this stack is empty.
  +   */
  +  public void quickPop(int n) 
  +  {
  +    m_firstFree -= n;
     }
   
  +
     /**
      * Looks at the object at the top of this stack without removing it 
      * from the stack. 
  @@ -127,10 +136,8 @@
       return elementAt(len - 1);
     }
   
  /**
  -   * Looks at the object at the top of this stack without removing it 
  -   * from the stack. 
  +   * Sets an object at a the top of the statck 
      *
  -   * @return     the object at the top of this stack. 
      * @exception  EmptyStackException  if this stack is empty.
      * @since      JDK1.0
      */
  
  
  
  1.2       +2 -2      xml-xalan/src/org/apache/xalan/xpath/xml/IntVector.java
  
  Index: IntVector.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xpath/xml/IntVector.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- IntVector.java	1999/12/13 07:40:11	1.1
  +++ IntVector.java	2000/02/13 16:42:43	1.2
  @@ -62,8 +62,8 @@
   public class IntVector
   {
     private int m_blocksize;
  -  private int m_map[];
  -  private int m_firstFree = 0;
  +  public int m_map[];  // expose to package for direct access.
  +  protected int m_firstFree = 0;
     private int m_mapSize;
   
     /**
  
  
  
  1.4       +1 -1      xml-xalan/src/org/apache/xalan/xpath/xml/NodeVector.java
  
  Index: NodeVector.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xpath/xml/NodeVector.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- NodeVector.java	2000/01/31 08:08:51	1.3
  +++ NodeVector.java	2000/02/13 16:42:43	1.4
  @@ -64,7 +64,7 @@
   public class NodeVector
   {
     private int m_blocksize;
  -  private Node m_map[];
  +  protected Node m_map[];
     private int m_firstFree = 0;
     private int m_mapSize;
   
  
  
  
  1.20      +22 -68    xml-xalan/src/org/apache/xalan/xpath/xml/XMLParserLiaisonDefault.java
  
  Index: XMLParserLiaisonDefault.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xpath/xml/XMLParserLiaisonDefault.java,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- XMLParserLiaisonDefault.java	2000/01/31 08:23:35	1.19
  +++ XMLParserLiaisonDefault.java	2000/02/13 16:42:43	1.20
  @@ -127,7 +127,6 @@
       m_sourceDocs = new Hashtable();
       m_formatterListener = null;
       m_dataProviders = new Vector(1);
  -    m_contextNodeList = null;
     }
   
     /**
  @@ -182,6 +181,12 @@
      * @see extensions.html.
      */
     public Hashtable m_extensionFunctionNamespaces = new Hashtable();
  +  
  +    /**
  +   * The table of extension namespaces.
  +   * @serial
  +   */
  +  public Hashtable m_extensionNamespaces = new Hashtable();
   
     /**
      * Table of input documents.
  @@ -241,7 +246,7 @@
      * The object will be set to null after the next LocationPath or 
      * Union is processed.
      */
  -  private Object m_callbackInfo = null;
  +  private Object m_callbackInfo = null;    
   
     /**
      * Set a callback that may be called by XPath as nodes are located.
  @@ -556,6 +561,7 @@
         stream.defaultReadObject();
         m_NSInfos = new Hashtable();
         m_extensionFunctionNamespaces = new Hashtable();
  +      m_extensionNamespaces = new Hashtable();
         m_sourceDocs = new Hashtable();
       }
       catch(ClassNotFoundException cnfe)
  @@ -1697,72 +1703,7 @@
     // SECTION: Execution context state tracking
     //==========================================================
     private final void ____Execution_Context____(){}
  -  
  -  /**
  -   * The current context node.
  -   */
  -  private NodeList m_contextNodeList = null;
  -  
  -  /**
  -   * The current node.
  -   */
  -  private Node m_currentNode = null;
  -  
  -  /**
  -   * The current prefixResolver for the execution context (not
  -   * the source tree context).
  -   * (Is this really needed?)
  -   */
  -  private PrefixResolver m_currentPrefixResolver = null;
  -  
  -  /**
  -   * Get the current context node list.
  -   */
  -  public NodeList getContextNodeList()
  -  {
  -    return m_contextNodeList;
  -  }
  -  
  -  /**
  -   * Set the current context node list.
  -   */
  -  public void setContextNodeList(NodeList nl)
  -  {
  -    m_contextNodeList = nl;
  -  }
  -  
  -  /**
  -   * Get the current context node.
  -   */
  -  public Node getCurrentNode()
  -  {
  -    return m_currentNode;
  -  }
  -
  -  /**
  -   * Set the current context node.
  -   */
  -  public void setCurrentNode(Node n)
  -  {
  -    m_currentNode = n;
  -  }
  -  
  -  /**
  -   * Get the current namespace context for the xpath.
  -   */
  -  public PrefixResolver getNamespaceContext()
  -  {
  -    return m_currentPrefixResolver;
  -  }
  -
  -  /**
  -   * Get the current namespace context for the xpath.
  -   */
  -  public void setNamespaceContext(PrefixResolver pr)
  -  {
  -    m_currentPrefixResolver = pr;
  -  }
  -  
  +    
     public NodeList getNodeSetByKey(Node doc, String name, 
                              String ref, 
                              org.apache.xalan.xpath.xml.PrefixResolver nscontext)
  @@ -1803,6 +1744,19 @@
     public void addExtensionNamespace (String uri,
            ExtensionFunctionHandler extNS) {
       m_extensionFunctionNamespaces.put (uri, extNS);
  +  }
  +
  +  /**
  +   * Register an element extension namespace handler. This handler provides
  +   * functions for testing whether a function is known within the 
  +   * namespace and also for invoking the functions.
  +   *
  +   * @param uri the URI for the extension.
  +   * @param extNS the extension handler.
  +   */
  +  public void addExtensionElementNamespace (String uri,
  +         ExtensionFunctionHandler extNS) {
  +    m_extensionNamespaces.put (uri, extNS);
     }
   
     /**
  
  
  
  1.3       +1 -1      xml-xalan/src/org/apache/xalan/xslt/AVTPartXPath.java
  
  Index: AVTPartXPath.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xslt/AVTPartXPath.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- AVTPartXPath.java	1999/11/28 04:25:13	1.2
  +++ AVTPartXPath.java	2000/02/13 16:42:44	1.3
  @@ -91,7 +91,7 @@
       m_xpath = factory.create();
   
       xpathProcessor.initMatchPattern(m_xpath, val, nsNode);
  -    m_xpath.shrink();
  +    // m_xpath.shrink();
     }
     
     /**
  
  
  
  1.3       +56 -0     xml-xalan/src/org/apache/xalan/xslt/Counter.java
  
  Index: Counter.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xslt/Counter.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Counter.java	2000/01/31 20:52:30	1.2
  +++ Counter.java	2000/02/13 16:42:44	1.3
  @@ -1,3 +1,59 @@
  +/*
  + * 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 "XSLT4J" 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 apache@apache.org.
  + *
  + * 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.xalan.xslt;
   
   import org.w3c.dom.Node;
  
  
  
  1.2       +56 -0     xml-xalan/src/org/apache/xalan/xslt/CountersTable.java
  
  Index: CountersTable.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xslt/CountersTable.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- CountersTable.java	2000/01/31 08:01:09	1.1
  +++ CountersTable.java	2000/02/13 16:42:44	1.2
  @@ -1,3 +1,59 @@
  +/*
  + * 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 "XSLT4J" 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 apache@apache.org.
  + *
  + * 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.xalan.xslt;
   
   import java.util.Hashtable;
  
  
  
  1.5       +17 -12    xml-xalan/src/org/apache/xalan/xslt/ElemCallTemplate.java
  
  Index: ElemCallTemplate.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xslt/ElemCallTemplate.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- ElemCallTemplate.java	2000/01/05 23:05:30	1.4
  +++ ElemCallTemplate.java	2000/02/13 16:42:44	1.5
  @@ -114,18 +114,23 @@
       }
       if(null != m_template)
       {
  -      processor.m_variableStacks.pushContextMarker(m_template, sourceNode);
  -      
  -      processor.m_variableStacks.pushParams(processor.getExecContext(),
  -                                            m_stylesheet, 
  -                                            this, 
  -                                            sourceTree, 
  -                                            sourceNode, mode, m_template);
  -      
  -      // template.executeChildren(processor, sourceTree, sourceNode, mode);
  -      m_template.execute(processor, sourceTree, sourceNode, mode);
  -      
  -      processor.m_variableStacks.popCurrentContext();
  +      try
  +      {
  +        processor.m_variableStacks.pushContextMarker(m_template, sourceNode);
  +        
  +        processor.m_variableStacks.pushParams(processor.getExecContext(),
  +                                              m_stylesheet, 
  +                                              this, 
  +                                              sourceTree, 
  +                                              sourceNode, mode, m_template);
  +        
  +        // template.executeChildren(processor, sourceTree, sourceNode, mode);
  +        m_template.execute(processor, sourceTree, sourceNode, mode);
  +      }
  +      finally
  +      {
  +        processor.m_variableStacks.popCurrentContext();
  +      }
       }
       else
       {
  
  
  
  1.5       +30 -3     xml-xalan/src/org/apache/xalan/xslt/ElemExtensionCall.java
  
  Index: ElemExtensionCall.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xslt/ElemExtensionCall.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- ElemExtensionCall.java	1999/12/14 00:21:54	1.4
  +++ ElemExtensionCall.java	2000/02/13 16:42:44	1.5
  @@ -63,19 +63,25 @@
   import org.apache.xalan.xpath.xml.QName;
   import org.apache.xalan.xpath.xml.NameSpace;
   import org.apache.xalan.xpath.xml.StringToStringTable;
  +import org.apache.xalan.xpath.xml.XMLParserLiaisonDefault;
   
   import java.io.*;
   import java.util.*;
   
   public class ElemExtensionCall extends ElemLiteralResult
   {
  -  ExtensionNSHandler nsh;
  +  // ExtensionNSHandler nsh;
  +  String m_extns;
  +  String m_extHandlerLookup;
     String localPart;
     AttributeList m_attrs;
     public Vector m_avts = null;
     public StringToStringTable m_excludeResultPrefixes = null;
     public String m_extensionElementPrefixes[] = null;
     transient boolean isAvailable = false;
  +  String m_lang;
  +  String m_srcURL;
  +  String m_scriptSrc;
   
     public int getXSLToken()
     {
  @@ -84,7 +90,9 @@
   
     ElemExtensionCall(XSLTEngineImpl processor, 
                       Stylesheet stylesheetTree,
  -                    ExtensionNSHandler nsh,
  +                    // ExtensionNSHandler nsh,
  +                    String extns,
  +                    String lang, String srcURL, String scriptSrc,
                       String name, 
                       String localPart,
                       AttributeList atts,
  @@ -93,7 +101,14 @@
     {
       super(processor, stylesheetTree, name, atts, lineNumber, columnNumber);
           
  -    this.nsh = nsh;
  +    m_extHandlerLookup = new String("ElemExtensionCall:"+extns);
  +    m_extns = extns;
  +    m_lang = lang;
  +    m_srcURL = srcURL;
  +    m_scriptSrc = scriptSrc;
  +
  +    // this.nsh = nsh;
  +    // processor.getXMLProcessorLiaison().addExtensionNamespace(m_extHandlerLookup, nsh);
       this.localPart = localPart;
       m_attrs = new AttributeListImpl(atts);
       int nAttrs = atts.getLength();
  @@ -171,6 +186,16 @@
       try
       {
         processor.flushPending();
  +      XMLParserLiaisonDefault liaison = ((XMLParserLiaisonDefault)processor.getXMLProcessorLiaison());
  +      ExtensionNSHandler nsh 
  +        = (ExtensionNSHandler)liaison.m_extensionNamespaces.get(m_extns);
  +
  +      if(null == nsh)
  +      {
  +        nsh = new ExtensionNSHandler (processor, m_extns);
  +        nsh.setScript (m_lang, m_srcURL, m_scriptSrc);
  +        liaison.addExtensionElementNamespace(m_extns, nsh);
  +      }
         nsh.processElement (localPart, this,
                             processor, 
                             m_stylesheet,
  @@ -186,6 +211,8 @@
             msg = msg.substring("Stopping after fatal error:".length());
           }
           processor.message("Call to extension element failed: "+msg);
  +        // e.printStackTrace();
  +        // System.exit(-1);
         }
         // processor.message(msg);
         isAvailable = false; 
  
  
  
  1.16      +54 -53    xml-xalan/src/org/apache/xalan/xslt/ElemTemplateElement.java
  
  Index: ElemTemplateElement.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xslt/ElemTemplateElement.java,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- ElemTemplateElement.java	2000/02/11 23:07:50	1.15
  +++ ElemTemplateElement.java	2000/02/13 16:42:44	1.16
  @@ -748,18 +748,22 @@
       if(null != selectPattern)
       {
         XPathSupport execContext = tcontext.getXMLProcessorLiaison();
  -      if(null != callback)
  -        execContext.setCallback(callback, 
  -                                new TemplateElementContext(stylesheetTree, 
  -                                                           xslInstruction, 
  -                                                           template, 
  -                                                           sourceNodeContext,
  -                                                           mode, 
  -                                                           xslToken, 
  -                                                           tcontext));
         
  +      // Optimization note: is there a way we can keep from creating 
  +      // a new callback context every time?
  +      TemplateElementContext callbackContext 
  +        = (null != callback) 
  +          ? new TemplateElementContext(stylesheetTree, 
  +                                       xslInstruction, 
  +                                       template, 
  +                                       sourceNodeContext,
  +                                       mode, 
  +                                       xslToken, 
  +                                       tcontext) : null;
  +      
         XObject result = selectPattern.execute(execContext, sourceNodeContext, 
  -                                             xslInstruction);
  +                                             xslInstruction, callback, 
  +                                             callbackContext, false);
         if(null != result)
         {
           sourceNodes = result.nodeset();
  @@ -803,28 +807,33 @@
           }
           
           // NodeList children = sourceNodeContext.getChildNodes(); 
  -        NodeList savedContextNodeList = tcontext.getExecContext().getContextNodeList();
  -        tcontext.getExecContext().setContextNodeList( sourceNodes );
  -        if(tcontext.m_traceSelects)
  -          tcontext.traceSelect(xslInstruction, sourceNodes);
  -        
  -        for(int i = 0; i < nNodes; i++) 
  +        tcontext.getExecContext().pushContextNodeList( sourceNodes );
  +        try
           {
  -          Node childNode = sourceNodes.item(i);
  +          if(tcontext.m_traceSelects)
  +            tcontext.traceSelect(xslInstruction, sourceNodes);
             
  -          Document ownerDoc = childNode.getOwnerDocument();
  -          if((Node.DOCUMENT_NODE != childNode.getNodeType()) && (null == ownerDoc))
  +          for(int i = 0; i < nNodes; i++) 
             {
  -            error(XSLTErrorResources.ER_NO_OWNERDOC, null); //"Child node does not have an owner document!");
  +            Node childNode = sourceNodes.item(i);
  +            
  +            Document ownerDoc = childNode.getOwnerDocument();
  +            if((Node.DOCUMENT_NODE != childNode.getNodeType()) && (null == ownerDoc))
  +            {
  +              error(XSLTErrorResources.ER_NO_OWNERDOC, null); //"Child node does not have an owner document!");
  +            }
  +            
  +            transformChild(
  +                           stylesheetTree, xslInstruction, template, 
  +                           ownerDoc, 
  +                           sourceNodeContext, childNode,
  +                           mode, xslToken, tcontext);
             }
  -          
  -          transformChild(
  -                         stylesheetTree, xslInstruction, template, 
  -                         ownerDoc, 
  -                         sourceNodeContext, childNode,
  -                         mode, xslToken, tcontext);
  +        }
  +        finally
  +        {
  +          tcontext.getExecContext().popContextNodeList();
           }
  -        tcontext.getExecContext().setContextNodeList( savedContextNodeList );
         }
       }
       else if(null == selectPattern)
  @@ -836,31 +845,10 @@
         {
           error(XSLTErrorResources.ER_NO_OWNERDOC, null); //"Child node does not have an owner document!");
         }
  -      NodeList savedContextNodeList = tcontext.getExecContext().getContextNodeList();
  -      MutableNodeList contextNodeList = new MutableNodeListImpl();
  -      tcontext.getExecContext().setContextNodeList( contextNodeList );
  -      /*
  -      // This isn't much faster than the block below...
         try
         {
  -        org.apache.xalan.xpath.dtm.DTMProxy contextp = (org.apache.xalan.xpath.dtm.DTMProxy)sourceNodeContext;
  -        org.apache.xalan.xpath.dtm.DTM dtm = contextp.getDTM();
  -        int contextIndex = contextp.getDTMNodeNumber();
  -        for(int child = dtm.getFirstChild(contextIndex); 
  -            child != -1; child = dtm.getNextSibling(child)) 
  -        {
  -            Node childNode = dtm.getNode(child);
  -            contextNodeList.addNode(childNode);
  -            transformChild(
  -                           stylesheetTree, xslInstruction, template, 
  -                           ownerDoc, 
  -                           sourceNodeContext, childNode,
  -                           mode, xslToken, tcontext);
  -        }
  -      }
  -      catch(ClassCastException cce)
  -      */
  -      {
  +        MutableNodeList contextNodeList = new MutableNodeListImpl();
  +        tcontext.getExecContext().pushContextNodeList( contextNodeList );
           for(Node childNode = sourceNodeContext.getFirstChild(); 
               null != childNode; childNode = childNode.getNextSibling()) 
           {
  @@ -877,7 +865,10 @@
                            mode, xslToken, tcontext);
           }
         }
  -      tcontext.getExecContext().setContextNodeList( savedContextNodeList );
  +      finally
  +      {
  +        tcontext.getExecContext().popContextNodeList();
  +      }
       }
     }
     
  @@ -944,15 +935,25 @@
                        templateContext.m_xslToken,
                        templateContext.m_transformContext
                        );
  +    }
  +    catch(java.net.MalformedURLException mue)
  +    {
  +      throw new XSLProcessorException(mue);
  +    }
  +    catch(java.io.FileNotFoundException fnfe)
  +    {
  +      throw new XSLProcessorException(fnfe);
       }
  -    catch(SAXException se)
  +    catch(java.io.IOException ioe)
       {
  -      throw se;
  +      throw new XSLProcessorException(ioe);
       }
  +    /*
       catch(Exception mue)
       {
         throw new XSLProcessorException(mue);
       }
  +    */
     }
       
     /** 
  
  
  
  1.4       +2 -1      xml-xalan/src/org/apache/xalan/xslt/ElemValueOf.java
  
  Index: ElemValueOf.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xslt/ElemValueOf.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- ElemValueOf.java	2000/01/05 23:05:32	1.3
  +++ ElemValueOf.java	2000/02/13 16:42:44	1.4
  @@ -179,7 +179,8 @@
       }
       else
       {
  -      XObject value = m_selectPattern.execute(processor.getExecContext(), sourceNode, this);
  +      XObject value = m_selectPattern.execute(processor.getExecContext(), sourceNode, this,
  +                                              null, null, true);
         
         if(null != m_stylesheet.m_stylesheetRoot.m_traceListeners)
         {
  
  
  
  1.26      +2 -2      xml-xalan/src/org/apache/xalan/xslt/Stylesheet.java
  
  Index: Stylesheet.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xslt/Stylesheet.java,v
  retrieving revision 1.25
  retrieving revision 1.26
  diff -u -r1.25 -r1.26
  --- Stylesheet.java	2000/02/09 20:11:11	1.25
  +++ Stylesheet.java	2000/02/13 16:42:44	1.26
  @@ -1340,7 +1340,7 @@
       XPath xpath = m_xpathFactory.create();
   
       m_xpathProcessor.initXPath(xpath, str, nsNode);
  -    xpath.shrink();
  +    // xpath.shrink();
       return xpath;
     }
   
  @@ -1365,7 +1365,7 @@
       XPath xpath = m_xpathFactory.create();
   
       m_xpathProcessor.initMatchPattern(xpath, str, nsNode);
  -    xpath.shrink();
  +    // xpath.shrink();
       return xpath;
     }
     
  
  
  
  1.16      +13 -1     xml-xalan/src/org/apache/xalan/xslt/StylesheetHandler.java
  
  Index: StylesheetHandler.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xslt/StylesheetHandler.java,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- StylesheetHandler.java	2000/02/10 20:06:31	1.15
  +++ StylesheetHandler.java	2000/02/13 16:42:44	1.16
  @@ -220,6 +220,7 @@
         Locator locator = (Locator)m_processor.m_stylesheetLocatorStack.pop();
         // System.out.println("popping locator for: "+locator.getPublicId());
       }
  +    m_stylesheet.m_extensionNamespaces.clear();
     }
     
     /** 
  @@ -1025,6 +1026,7 @@
           // BEGIN SANJIVA CODE
           // is this an extension element call?
           ExtensionNSHandler nsh = null;
  +        String theExtns = null;
           
           if(null != ns)
           {
  @@ -1058,6 +1060,7 @@
                         if((ns != null) && ns.equals(extns))
                         {
                           nsh = new ExtensionNSHandler (m_processor, extns);
  +                        theExtns = extns;
                           break;
                         }
                       }
  @@ -1095,6 +1098,7 @@
                     if((ns != null) && ns.equals(extns))
                     {
                       nsh = new ExtensionNSHandler (m_processor, extns);
  +                    theExtns = extns;
                       break;
                     }
                   }
  @@ -1107,13 +1111,21 @@
           if ((ns != null) && (null == nsh)) 
           {
             nsh = m_stylesheet.lookupExtensionNSHandler(ns);
  +          theExtns = ns;
           }
           
           if (nsh != null) 
           {
  +          if(null == theExtns)
  +            theExtns = "";
  +          
             elem = new ElemExtensionCall (m_processor,
                                           m_stylesheet,
  -                                        nsh,
  +                                        // nsh,
  +                                        theExtns,
  +                                        nsh.scriptLang,
  +                                        nsh.scriptSrcURL,
  +                                        nsh.scriptSrc,
                                           name,
                                           localName,
                                           atts, lineNumber, columnNumber);
  
  
  
  1.36      +10 -0     xml-xalan/src/org/apache/xalan/xslt/XSLTEngineImpl.java
  
  Index: XSLTEngineImpl.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xslt/XSLTEngineImpl.java,v
  retrieving revision 1.35
  retrieving revision 1.36
  diff -u -r1.35 -r1.36
  --- XSLTEngineImpl.java	2000/02/11 15:42:39	1.35
  +++ XSLTEngineImpl.java	2000/02/13 16:42:44	1.36
  @@ -3313,6 +3313,16 @@
     {
       m_flistener = flistener;
     }
  +  
  +  /**
  +   * Set a DOM document factory, primarily for creating result
  +   * tree fragments.
  +   */
  +  public void setDOMFactory(Document doc)
  +  {
  +    m_resultTreeFactory = doc;
  +  }
  +
   
     /**
      * Get a DOM document, primarily for creating result