mmidy       00/11/30 08:26:50

  Modified:    java/src/org/apache/xalan/stree StreeDOMBuilder.java
               java/src/org/apache/xalan/transformer KeyIterator.java
                        KeyTable.java KeyWalker.java
               java/src/org/apache/xpath/axes LocPathIterator.java
  Added:       java/src/org/apache/xalan/transformer KeyRefIterator.java
  Log:
  Change Key() to incrementally build a table with key values and iterators. 
With this change, we will only walk through the source tree once per key name 
definition.
  
  Revision  Changes    Path
  1.8       +3 -0      
xml-xalan/java/src/org/apache/xalan/stree/StreeDOMBuilder.java
  
  Index: StreeDOMBuilder.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xalan/stree/StreeDOMBuilder.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- StreeDOMBuilder.java      2000/11/23 04:57:39     1.7
  +++ StreeDOMBuilder.java      2000/11/30 16:26:48     1.8
  @@ -323,6 +323,9 @@
      */
     void appendAccumulatedText(Node currentNode, char ch[], int start, int 
length)
     {
  +    // Get the text node. It should be the last node that was 
  +    // added to the current node. (Text nodes are never made to be
  +    // the currentNode).
       TextImpl textNode = (TextImpl)((Parent)currentNode).m_last;
       textNode.appendText(ch, start, length);
     }
  
  
  
  1.7       +52 -0     
xml-xalan/java/src/org/apache/xalan/transformer/KeyIterator.java
  
  Index: KeyIterator.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xalan/transformer/KeyIterator.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- KeyIterator.java  2000/11/23 04:58:16     1.6
  +++ KeyIterator.java  2000/11/30 16:26:48     1.7
  @@ -81,9 +81,18 @@
    */
   public class KeyIterator extends LocPathIterator
   {
  +  
  +  /** The key table this iterator is associated to          */
  +  private KeyTable m_keyTable;
   
     /** NEEDSDOC Field m_name          */
     private QName m_name;
  +  
  +  /** 
  +   * Flag indicating whether the whole source tree has been walked.     
  +   * True if we still need to finish walking the tree.
  +   * */
  +  private boolean m_lookForMoreNodes = true;
   
     /**
      * NEEDSDOC Method getName 
  @@ -172,4 +181,47 @@
       this.setLastUsedWalker(m_firstWalker);
       this.setNextPosition(0);
     }
  +  
  +  /**
  +   * Set the KeyTable associated with this iterator  
  +   *
  +   *
  +   * @param keyTable, the KeyTable associated with this iterator
  +   */
  +  void setKeyTable(KeyTable keyTable)
  +  {
  +    m_keyTable = keyTable;
  +  }  
  +  
  +  /**
  +   * Add this ref to the refsTable in KeyTable  
  +   *
  +   *
  +   * @param ref Key ref(from key use field)
  +   * @param node Node matching that ref 
  +   */
  +  void addRefNode(String ref, Node node)
  +  {
  +    m_keyTable.addRefNode(ref, node);
  +  }
  +  
  +  /**
  +   * Indicate whether we have walked the whole tree  
  +   *
  +   * @param b False if we have walked the whole tree
  +   */
  +  void setLookForMoreNodes(boolean b)
  +  {
  +    m_lookForMoreNodes = b;
  +  }
  +  
  +  /**
  +   * Get flag indicating whether we have walked the whole tree  
  +   *
  +   */
  +  boolean getLookForMoreNodes()
  +  {
  +    return m_lookForMoreNodes;
  +  }
  +  
   }
  
  
  
  1.7       +83 -11    
xml-xalan/java/src/org/apache/xalan/transformer/KeyTable.java
  
  Index: KeyTable.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xalan/transformer/KeyTable.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- KeyTable.java     2000/11/23 04:58:16     1.6
  +++ KeyTable.java     2000/11/30 16:26:48     1.7
  @@ -63,6 +63,7 @@
   
   import java.util.Hashtable;
   import java.util.Vector;
  +import java.util.Enumeration;
   
   import org.apache.xpath.NodeSet;
   import org.apache.xpath.objects.XObject;
  @@ -111,6 +112,8 @@
      * b) with a value that is a KeyIterator.
      */
     private KeyIterator m_keyIter;
  +  
  +  private Hashtable defsTable;
   
     /**
      * Build a keys table.
  @@ -131,35 +134,64 @@
       m_docKey = doc;
       m_keyIter = new KeyIterator(doc, nscontext, name, keyDeclarations,
                                   xmlLiaison);
  +    m_keyIter.setKeyTable(this);
     }  // end buildKeysTable method
   
     /**
      * Given a valid element key, return the corresponding node list.
      * @param The name of the key, which must match the 'name' attribute on 
xsl:key.
      *
  -   * NEEDSDOC @param name
  +   * @param name The name of the key
      * @param ref The value that must match the value found by the 'match' 
attribute on xsl:key.
      * @return If the name was not declared with xsl:key, this will return 
null,
      * if the identifier is not found, it will return null,
      * otherwise it will return a LocPathIterator instance.
      */
  -  public KeyIterator getNodeSetByKey(QName name, String ref)
  +  public LocPathIterator getNodeSetByKey(QName name, String ref)
     {
   
       KeyIterator ki;
  -
  -    try
  -    {
  -      ki = (KeyIterator) m_keyIter.clone();
  +    KeyRefIterator kiRef;
  +    Hashtable refsTable = null;
   
  -      ki.setLookupKey(ref);
  -    }
  -    catch (CloneNotSupportedException cnse)
  +    if (defsTable != null)
       {
  -      ki = null;
  +      refsTable = (Hashtable)defsTable.get(name);
  +      if (refsTable != null)
  +      {
  +        Object kiObj = refsTable.get(ref);
  +        if (kiObj != null)
  +        {
  +          try
  +          {
  +            // clone with reset??
  +            kiRef = (KeyRefIterator)((KeyRefIterator)kiObj).clone();
  +            return kiRef;
  +          }
  +          catch (CloneNotSupportedException cnse)
  +          {
  +            ki = null;
  +          }
  +        }
  +      }
       }
   
  -    return ki;
  +    {
  +      if (defsTable == null)
  +        defsTable = new Hashtable();
  +      if (refsTable == null)
  +        refsTable = new Hashtable();
  +      
  +      // initialize walker only once!
  +      if (m_keyIter.getFirstWalker().getRoot() == null)
  +        m_keyIter.setLookupKey(ref);
  +      else
  +        ((KeyWalker)m_keyIter.getFirstWalker()).m_lookupKey = ref;
  +      kiRef = new KeyRefIterator(ref, m_keyIter);
  +      refsTable.put(ref, kiRef);
  +      defsTable.put(name,refsTable);
  +      return kiRef;              
  +    } 
     }
   
     /**
  @@ -172,4 +204,44 @@
     {
       return m_keyIter.getName();
     }
  +  
  +  /**
  +   * Add this ref to the refsTable  
  +   *
  +   *
  +   * @param ref Key ref(from key use field)
  +   * @param node Node matching that ref 
  +   */
  +  void addRefNode(String ref, Node node)
  +  {
  +    KeyRefIterator kiRef = null;
  +    Hashtable refsTable = null;
  +    if (defsTable != null)
  +    {
  +      refsTable = (Hashtable)defsTable.get(getKeyTableName());
  +      if (refsTable != null)
  +      {
  +        Object kiObj = refsTable.get(ref);
  +        if (kiObj != null)
  +        {          
  +          kiRef = (KeyRefIterator)kiObj;            
  +        }
  +      }
  +    }
  +    if (kiRef == null)
  +    {  
  +      if (defsTable == null)
  +        defsTable = new Hashtable();
  +      if (refsTable == null)
  +      {  
  +        refsTable = new Hashtable();
  +        defsTable.put(getKeyTableName(),refsTable);
  +      }
  +      kiRef = new KeyRefIterator(ref, m_keyIter);
  +      refsTable.put(ref, kiRef);      
  +    }
  +    kiRef.addNode(node); 
  +  }
  +  
  +  
   }
  
  
  
  1.9       +43 -7     
xml-xalan/java/src/org/apache/xalan/transformer/KeyWalker.java
  
  Index: KeyWalker.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xalan/transformer/KeyWalker.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- KeyWalker.java    2000/11/23 04:58:16     1.8
  +++ KeyWalker.java    2000/11/30 16:26:49     1.9
  @@ -194,8 +194,8 @@
                                                      testNode);
   
           if (score == kd.getMatch().MATCH_SCORE_NONE)
  -          continue;
  -
  +          continue;        
  +                
           // Query from the node, according the the select pattern in the
           // use attribute in xsl:key.
           XObject xuse = kd.getUse().execute(ki.getXPathContext(), testNode,
  @@ -204,7 +204,8 @@
           if (xuse.getType() != xuse.CLASS_NODESET)
           {
             String exprResult = xuse.str();
  -
  +          ((KeyIterator)m_lpi).addRefNode(exprResult, testNode);
  +          
             if (lookupKey.equals(exprResult))
               return this.FILTER_ACCEPT;
           }
  @@ -212,15 +213,32 @@
           {
             NodeIterator nl = xuse.nodeset();
             Node useNode;
  -
  +          short result = -1;
  +          /*
  +          We are walking through all the nodes in this nodeset
  +          rather than stopping when we find the one we're looking
  +          for because we don't currently save the state of KeyWalker
  +          such that the next time it gets called it would continue
  +          to look in this nodeset for any further matches. 
  +          TODO: Try to save the state of KeyWalker, i.e. keep this node
  +          iterator saved somewhere and finish walking through its nodes
  +          the next time KeyWalker is called before we look for any new
  +          matches. What if the next call is for the same match+use 
  +          combination??
  +          */
             while (null != (useNode = nl.nextNode()))
             {
               String exprResult = m_lpi.getDOMHelper().getNodeData(useNode);
  -
  +            ((KeyIterator)m_lpi).addRefNode(exprResult, testNode); 
  +            
               if ((null != exprResult) && lookupKey.equals(exprResult))
  -              return this.FILTER_ACCEPT;
  +              result = this.FILTER_ACCEPT;
  +              //return this.FILTER_ACCEPT;
             }
  -        }
  +          if (-1 != result)
  +            return result;
  +        }       
  +        
         }  // end for(int i = 0; i < nDeclarations; i++)
       }
       catch (TransformerException se)
  @@ -231,4 +249,22 @@
   
       return this.FILTER_REJECT;
     }
  +  
  +   /**
  +   *  Moves the <code>TreeWalker</code> to the next visible node in document
  +   * order relative to the current node, and returns the new node. If the
  +   * current node has no next node,  or if the search for nextNode attempts
  +   * to step upward from the TreeWalker's root node, returns
  +   * <code>null</code> , and retains the current node.
  +   * @return  The new node, or <code>null</code> if the current node has no
  +   *   next node  in the TreeWalker's logical view.
  +   */
  +  public Node nextNode()
  +  {
  +    Node node = super.nextNode();
  +    if (node == null)
  +      ((KeyIterator)m_lpi).setLookForMoreNodes(false);
  +    return node;
  +  }
  +  
   }
  
  
  
  1.1                  
xml-xalan/java/src/org/apache/xalan/transformer/KeyRefIterator.java
  
  Index: KeyRefIterator.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:  
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Xalan" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written 
   *    permission, please contact [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation and was
   * originally based on software copyright (c) 1999, Lotus
   * Development Corporation., http://www.lotus.com.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.xalan.transformer;
  
  import java.util.Vector;
  
  import org.apache.xpath.axes.LocPathIterator;
  import org.apache.xml.utils.QName;
  import org.apache.xalan.templates.KeyDeclaration;
  import org.apache.xpath.NodeSet;
  
  import org.w3c.dom.Node;
  import org.w3c.dom.DOMException;
  
  /**
   * <meta name="usage" content="internal"/>
   * NEEDSDOC Class KeyIterator <needs-comment/>
   */
  public class KeyRefIterator extends LocPathIterator
  {
  
    /** Key name          */
    private QName m_name;    
    
    /** Use field of key function          */
    private String m_lookupKey;  
    
    /** Main Key iterator for this iterator     */
    private KeyIterator m_ki;    
    
    /**
     * Get key name
     *
     *
     * @return Key name
     */
    public QName getName()
    {
      return m_name;
    }
    
    
  
    /**
     * Constructor KeyRefIterator
     *
     *
     * NEEDSDOC @param doc
     * NEEDSDOC @param nscontext
     * NEEDSDOC @param name
     * NEEDSDOC @param keyDeclarations
     * NEEDSDOC @param xctxt
     */
    public KeyRefIterator(String ref, KeyIterator ki)
    {
  
      super(ki.getPrefixResolver());
      setShouldCacheNodes(true);
      m_ki = ki;
      m_name = ki.getName();
      m_lookupKey = ref;
      this.m_execContext = ki.getXPathContext();
      this.m_dhelper = ki.getDOMHelper();
    }
  
    /**
     *  Returns the next node in the set and advances the position of the
     * iterator in the set. After a NodeIterator is created, the first call
     * to nextNode() returns the first node in the set.
     * 
     * @return  The next <code>Node</code> in the set being iterated over, or
     *   <code>null</code> if there are no more members in that set.
     * 
     * @exception DOMException
     *    INVALID_STATE_ERR: Raised if this method is called after the
     *   <code>detach</code> method was invoked.
     */
    public Node nextNode() throws DOMException
    {
  
      if (m_foundLast)
        return null;
      
      // If the cache is on, and the node has already been found, then 
      // just return from the list.
      NodeSet m_cachedNodes = getCachedNodes();
      
      // We are not using the NodeSet methods getCurrentPos() and nextNode()
      // in this case because the nodeset is not cloned and therefore
      // the positions it indicates may not be associated with the 
      // current iterator.
      if ((null != m_cachedNodes)
              && (m_next < m_cachedNodes.size()))        
      {
        Node next = m_cachedNodes.elementAt(m_next); 
        this.setCurrentPos(++m_next); 
        m_lastFetched = next;
        return next;
      }    
  
      Node next = null;       
      if ( m_ki.getLookForMoreNodes()) 
      {
        ((KeyWalker)m_ki.getFirstWalker()).m_lookupKey = m_lookupKey;
        next = m_ki.nextNode();        
      }
      
      if (null != next)
      {  
        m_lastFetched = next;
        this.setCurrentPos(++m_next);
        return next;
      }
      else
        m_foundLast = true;                      
      
      m_lastFetched = null;
      return null;
    }
    
    /**
     * Get a cloned LocPathIterator that holds the same 
     * position as this iterator.
     *
     * @return A clone of this iterator that holds the same node position.
     *
     * @throws CloneNotSupportedException 
     */
    public Object clone() throws CloneNotSupportedException
    {
      KeyRefIterator clone = (KeyRefIterator)super.clone();
      clone.m_foundLast = false;
      clone.m_lastFetched = null;
      clone.m_next = 0; 
      clone.setCurrentPos(0);
      return clone;
    }
    
    /**
     * Add a node matching this ref to the cached nodes for this iterator 
     *
     *
     * @param node Node to add to cached nodes
     */
    public void addNode(Node node) 
    {
      NodeSet m_cachedNodes = getCachedNodes();
      if (null != m_cachedNodes)
        m_cachedNodes.addElement(node);
    }  
         
  }
  
  
  
  1.16      +11 -1     
xml-xalan/java/src/org/apache/xpath/axes/LocPathIterator.java
  
  Index: LocPathIterator.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xpath/axes/LocPathIterator.java,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- LocPathIterator.java      2000/11/23 04:59:01     1.15
  +++ LocPathIterator.java      2000/11/30 16:26:50     1.16
  @@ -111,7 +111,7 @@
     ObjectPool m_pool = new ObjectPool(this.getClass());
   
     /** The last node that was fetched, usually by nextNode. */
  -  Node m_lastFetched;
  +  public Node m_lastFetched;
   
     /** If this iterator needs to cache nodes that are fetched, they
      * are stored here.   */
  @@ -350,6 +350,16 @@
         m_cachedNodes = new NodeSet();
       else
         m_cachedNodes = null;
  +  }
  +  
  +  /**
  +   * Get cached nodes.
  +   *
  +   * @return Cached nodes.
  +   */
  +  public NodeSet getCachedNodes()
  +  {
  +    return m_cachedNodes;
     }
   
     /**
  
  
  

Reply via email to