You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by il...@apache.org on 2002/10/22 17:42:36 UTC

cvs commit: xml-xalan/java/src/org/apache/xpath/axes NodeSequence.java

ilene       2002/10/22 08:42:36

  Modified:    java/src/org/apache/xalan/transformer KeyTable.java
               java/src/org/apache/xpath/axes NodeSequence.java
  Log:
  Committing urban.spielmann@swisslife.ch (Urban Spielmann)'s  patch for bugzilla #11661.  
  
  After the Redundant Expression Elimination merge, the key cache had
  not yet been replaced.  This patch puts back the key cache, which
  gives xsl:key much better performance.
  
  Revision  Changes    Path
  1.13      +155 -22   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.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- KeyTable.java	15 Aug 2002 14:31:17 -0000	1.12
  +++ KeyTable.java	22 Oct 2002 15:42:36 -0000	1.13
  @@ -60,23 +60,28 @@
   import java.util.Vector;
   
   import javax.xml.transform.TransformerException;
  -import org.apache.xml.dtm.DTM;
  +
  +import org.apache.xml.utils.NodeVector;
   import org.apache.xml.utils.PrefixResolver;
   import org.apache.xml.utils.QName;
   import org.apache.xml.utils.XMLString;
  +import org.apache.xml.utils.WrappedRuntimeException;
  +import org.apache.xml.dtm.DTM;
  +import org.apache.xml.dtm.DTMIterator;
   import org.apache.xpath.XPathContext;
   import org.apache.xpath.objects.XNodeSet;
  +import org.apache.xpath.objects.XObject;
  +import org.apache.xpath.objects.XNull;
  +import org.apache.xalan.templates.KeyDeclaration;
   
   /**
    * <meta name="usage" content="advanced"/>
    * Table of element keys, keyed by document node.  An instance of this
    * class is keyed by a Document node that should be matched with the
  - * root of the current context.  It contains a table of name mappings
  - * to tables that contain mappings of identifier values to nodes.
  + * root of the current context.
    */
   public class KeyTable
   {
  -
     /**
      * The document key.  This table should only be used with contexts
      * whose Document roots match this key.
  @@ -84,9 +89,20 @@
     private int m_docKey;
   
     /**
  +   * Vector of KeyDeclaration instances holding the key declarations.
  +   */
  +  private Vector m_keyDeclarations;
  +
  +  /**
  +   * Hold a cache of key() function result for each ref.
  +   * Key is XMLString, the ref value
  +   * Value is XNodeSet, the key() function result for the given ref value.
  +   */
  +  private Hashtable m_refsTable = null;
  +
  +  /**
      * Get the document root matching this key.  
      *
  -   *
      * @return the document root matching this key
      */
     public int getDocKey()
  @@ -119,46 +135,163 @@
             int doc, PrefixResolver nscontext, QName name, Vector keyDeclarations, XPathContext xctxt)
               throws javax.xml.transform.TransformerException
     {
  -
       m_docKey = doc;
  +    m_keyDeclarations = keyDeclarations;
       KeyIterator ki = new KeyIterator(name, keyDeclarations);
  -    
  +
       m_keyNodes = new XNodeSet(ki);
       m_keyNodes.allowDetachToRelease(false);
  -    
       m_keyNodes.setRoot(doc, xctxt);
  -
  -  }  
  +  }
   
     /**
      * 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.
  +   * @param name The name of the key, which must match the 'name' attribute on xsl: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.
  +   * @return a set of nodes referenced by the key named <CODE>name</CODE> and the reference <CODE>ref</CODE>. If no node is referenced by this key, an empty node set is returned.
      */
     public XNodeSet getNodeSetDTMByKey(QName name, XMLString ref)
  +
     {
  -  	Vector keyDecls = getKeyIterator().getKeyDeclarations();
  -  	org.apache.xml.dtm.DTMIterator keyNodes = m_keyNodes.iter();
  -	XNodeSet refNodes = new XNodeSet( new KeyRefIterator(name, ref, keyDecls, keyNodes) );
  -	
  -	// I don't think setRoot needs to be called on refNodes!
  -	return refNodes;
  +    XNodeSet refNodes = (XNodeSet) getRefsTable().get(ref);
  +    // clone wiht reset the node set
  +   try
  +    {
  +      if (refNodes != null)
  +      {
  +         refNodes = (XNodeSet) refNodes.cloneWithReset();
  +       }
  +    }
  +    catch (CloneNotSupportedException e)
  +    {
  +      refNodes = null;
  +    }
  +
  +    if (refNodes == null) {
  +     //  create an empty XNodeSet
  +      KeyIterator ki = (KeyIterator) (m_keyNodes).getContainedIter();
  +      XPathContext xctxt = ki.getXPathContext();
  +      refNodes = new XNodeSet(xctxt.getDTMManager()) {
  +        public void setRoot(int nodeHandle, Object environment) {
  +          // Root cannot be set on non-iterated node sets. Ignore it.
  +        }
  +      };
  +      refNodes.reset();
  +    }
   
  +    return refNodes;
     }
   
     /**
      * Get Key Name for this KeyTable  
      *
  -   *
      * @return Key name
      */
     public QName getKeyTableName()
     {
       return getKeyIterator().getName();
     }
  -  
  +
  +  /**
  +   * @return key declaration for the key associated to this KeyTable
  +   */
  +  private KeyDeclaration getKeyDeclaration() {
  +    int nDeclarations = m_keyDeclarations.size();
  +
  +    // Walk through each of the declarations made with xsl:key
  +    for (int i = 0; i < nDeclarations; i++)
  +    {
  +      KeyDeclaration kd = (KeyDeclaration) m_keyDeclarations.elementAt(i);
  +
  +      // Only continue if the name on this key declaration
  +      // matches the name on the iterator for this walker.
  +      if (kd.getName().equals(getKeyTableName()))
  +      {
  +        return kd;
  +      }
  +    }
  +
  +    // should never happen
  +    return null;
  +  }
  +
  +  /**
  +   * @return lazy initialized refs table associating evaluation of key function
  +   *         with a XNodeSet
  +   */
  +  private Hashtable getRefsTable()
  +  {
  +    if (m_refsTable == null)
  +    {
  +      m_refsTable = new Hashtable(89);  // initial capacity set to a prime number to improve hash algorithm performance
  +
  +      KeyIterator ki = (KeyIterator) (m_keyNodes).getContainedIter();
  +      XPathContext xctxt = ki.getXPathContext();
  +
  +      KeyDeclaration keyDeclaration = getKeyDeclaration();
  +
  +      int currentNode;
  +      m_keyNodes.reset();
  +      while (DTM.NULL != (currentNode = m_keyNodes.nextNode()))
  +      {
  +        try
  +        {
  +          XObject xuse = keyDeclaration.getUse().execute(xctxt, currentNode, ki.getPrefixResolver());
  +
  +          if (xuse.getType() != xuse.CLASS_NODESET)
  +          {
  +            XMLString exprResult = xuse.xstr();
  +            addValueInRefsTable(xctxt, exprResult, currentNode);
  +          }
  +          else
  +          {
  +            DTMIterator i = ((XNodeSet)xuse).iterRaw();
  +            int currentNodeInUseClause;
  +
  +            while (DTM.NULL != (currentNodeInUseClause = i.nextNode()))
  +            {
  +              DTM dtm = xctxt.getDTM(currentNodeInUseClause);
  +              XMLString exprResult = dtm.getStringValue(currentNodeInUseClause);
  +              addValueInRefsTable(xctxt, exprResult, currentNode);
  +            }
  +          }
  +        }
  +        catch (TransformerException te)
  +        {
  +          throw new WrappedRuntimeException(te);
  +        }
  +      }
  +    }
  +    return m_refsTable;
  +  }
  +
  +  /**
  +   * Add an association between a ref and a node in the m_refsTable.
  +   * Requires that m_refsTable != null
  +   * @param xctxt XPath context
  +   * @param ref the value of the use clause of the current key for the given node
  +   * @param node the node to reference
  +   */
  +  private void addValueInRefsTable(XPathContext xctxt, XMLString ref, int node) {
  +    
  +    XNodeSet nodes = (XNodeSet) m_refsTable.get(ref);
  +    if (nodes == null)
  +    {
  +      nodes = new XNodeSet(node, xctxt.getDTMManager());
  +      nodes.nextNode();
  +      m_refsTable.put(ref, nodes);
  +    }
  +    else
  +    {
  +      // Nodes are passed to this method in document order.  Since we need to
  +      // suppress duplicates, we only need to check against the last entry
  +      // in each nodeset.  We use nodes.nextNode after each entry so we can
  +      // easily compare node against the current node.
  +      if (nodes.getCurrentNode() != node) {
  +          nodes.mutableNodeset().addNode(node);
  +          nodes.nextNode();
  +      }    
  +    }
  +  }
   }
  
  
  
  1.4       +4 -0      xml-xalan/java/src/org/apache/xpath/axes/NodeSequence.java
  
  Index: NodeSequence.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/axes/NodeSequence.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- NodeSequence.java	16 May 2002 16:19:49 -0000	1.3
  +++ NodeSequence.java	22 Oct 2002 15:42:36 -0000	1.4
  @@ -66,6 +66,7 @@
   import org.apache.xml.dtm.DTMFilter;
   import org.apache.xml.utils.NodeVector;
   import org.apache.xpath.Expression;
  +import org.apache.xpath.NodeSetDTM;
   import org.apache.xpath.XPathContext;
   import org.apache.xpath.objects.XObject;
   
  @@ -534,6 +535,9 @@
     {
     	if(hasCache())
     	{
  +        if (m_obj instanceof NodeSetDTM) {
  +            return ((NodeSetDTM)m_obj).getLength();
  +        }    
   	  	if(-1 == m_last)
   	  	{
   	  		int pos = m_next;
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: xalan-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: xalan-cvs-help@xml.apache.org