jkesselm    01/11/29 08:30:47

  Modified:    java/src/org/apache/xml/dtm/ref DTMDefaultBase.java
                        DTMManagerDefault.java
               java/src/org/apache/xml/dtm/ref/dom2dtm DOM2DTM.java
               java/src/org/apache/xpath XPathAPI.java
  Added:       java/src/org/apache/xpath CachedXPathAPI.java
  Log:
  Bugzilla 4336 -- fix for presenting symptom (since the implicit
  xml: declaration pseudo-DOM node is resynthesized in each
  DTM, find the _corresponding_ node), and a first draft of
  CachedXPathAPI which should be a fix for the larger symptom
  (XPathAPI creates a new DTM every time, which is potentially
  very ugly for applications that want to run XPaths repeatedly
  on a single document).
  
  Also caught and fixed another node-handle/node-identity confusion.
  The fact that DTM.get...() allowed us to be sloppy about that
  distinction in the past means there may still be a few others lurking
  in the code. Ye gods, I _wish_ Java had typedef!
  
  Revision  Changes    Path
  1.22      +1 -0      
xml-xalan/java/src/org/apache/xml/dtm/ref/DTMDefaultBase.java
  
  Index: DTMDefaultBase.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xml/dtm/ref/DTMDefaultBase.java,v
  retrieving revision 1.21
  retrieving revision 1.22
  diff -u -r1.21 -r1.22
  --- DTMDefaultBase.java       2001/11/26 22:08:28     1.21
  +++ DTMDefaultBase.java       2001/11/29 16:30:47     1.22
  @@ -915,6 +915,7 @@
       if(JJK_DEBUG && nodeHandle<DTMManager.IDENT_NODE_DEFAULT)
         System.err.println("GONK! (only useful in limited situations)");
          
  +             /**JJK*/int jjk=DTMManager.IDENT_DTM_DEFAULT;
       int whichDTMid=m_dtmIdent.indexOf(nodeHandle & 
DTMManager.IDENT_DTM_DEFAULT);
       return (whichDTMid==NULL) 
         ? NULL
  
  
  
  1.31      +37 -9     
xml-xalan/java/src/org/apache/xml/dtm/ref/DTMManagerDefault.java
  
  Index: DTMManagerDefault.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xml/dtm/ref/DTMManagerDefault.java,v
  retrieving revision 1.30
  retrieving revision 1.31
  diff -u -r1.30 -r1.31
  --- DTMManagerDefault.java    2001/11/26 22:08:28     1.30
  +++ DTMManagerDefault.java    2001/11/29 16:30:47     1.31
  @@ -116,7 +116,7 @@
     protected DTM m_dtms[] = new DTM[256];
        
        /** Map from DTM identifier numbers to offsets. For small DTMs with a 
  -      * single identifier, this will always be 0. In extended addressing, 
where
  +      * single identifier, this will always be 0. In overflow addressing, 
where
         * additional identifiers are allocated to access nodes beyond the 
range of
         * a single Node Handle, this table is used to map the handle's node 
field
         * into the actual node identifier.
  @@ -147,7 +147,7 @@
      * @param offset Integer addressing offset. The internal DTM Node ID is
      * obtained by adding this offset to the node-number field of the 
      * public DTM Handle. For the first DTM ID accessing each DTM, this is 0;
  -   * for extended addressing it will be a multiple of 1<<IDENT_DTM_NODE_BITS.
  +   * for overflow addressing it will be a multiple of 1<<IDENT_DTM_NODE_BITS.
      */
     public void addDTM(DTM dtm, int id, int offset)
     {
  @@ -475,6 +475,7 @@
   
       if (node instanceof org.apache.xml.dtm.ref.DTMNodeProxy)
         return ((org.apache.xml.dtm.ref.DTMNodeProxy) node).getDTMNodeNumber();
  +             
       else
       {
         // Find the DOM2DTMs wrapped around this Document (if any)
  @@ -489,10 +490,10 @@
         // %REVIEW% We could search for the one which contains this
         // node at the deepest level, and thus covers the widest
         // subtree, but that's going to entail additional work
  -      // checking more DTMs... and getHandleFromNode is not a
  +      // checking more DTMs... and getHandleOfNode is not a
         // cheap operation in most implementations.
                        //
  -                     // TODO: %REVIEW% If extended addressing, we may 
recheck a DTM
  +                     // TODO: %REVIEW% If overflow addressing, we may 
recheck a DTM
                        // already examined. Ouch. But with the increased 
number of DTMs,
                        // scanning back to check this is painful. 
                        // POSSIBLE SOLUTIONS: 
  @@ -508,8 +509,24 @@
               if(handle!=DTM.NULL) return handle;
             }
            }
  +
  +                     // Not found; generate a new DTM.
  +                     //
  +                     // %REVIEW% Is this really desirable, or should we 
return null
  +                     // and make folks explicitly instantiate from a 
DOMSource? The
  +                     // latter is more work but gives the caller the 
opportunity to
  +                     // explicitly add the DTM to a DTMManager... and thus 
to know when
  +                     // it can be discarded again, which is something we 
need to pay much
  +                     // more attention to. (Especially since only DTMs which 
are assigned
  +                     // to a manager can use the overflow addressing scheme.)
  +                     //
  +                     // %BUG% If the source node was a 
DOM2DTM$defaultNamespaceDeclarationNode
  +                     // and the DTM wasn't registered with this DTMManager, 
we will create
  +                     // a new DTM and _still_ not be able to find the node 
(since it will
  +                     // be resynthesized). Another reason to push hard on 
making all DTMs
  +                     // be managed DTMs.
   
  -      // Since the real root of our tree may be a DocumentFragment, we need 
to
  +                     // Since the real root of our tree may be a 
DocumentFragment, we need to
         // use getParent to find the root, instead of getOwnerDocument.  
Otherwise
         // DOM2DTM#getHandleOfNode will be very unhappy.
         Node root = node;
  @@ -519,10 +536,21 @@
           root = p;
         }
   
  -      DTM dtm = getDTM(new javax.xml.transform.dom.DOMSource(root), false,
  -                       null, true, true);
  +      DOM2DTM dtm = (DOM2DTM) getDTM(new 
javax.xml.transform.dom.DOMSource(root),
  +                                                                             
                                                                 false, null, 
true, true);
   
  -      int handle = ((DOM2DTM)dtm).getHandleOfNode(node);
  +      int handle;
  +      
  +      if(node instanceof 
org.apache.xml.dtm.ref.dom2dtm.DOM2DTMdefaultNamespaceDeclarationNode)
  +      {
  +                             // Can't return the same node since it's unique 
to a specific DTM, 
  +                             // but can return the equivalent node -- find 
the corresponding 
  +                             // Document Element, then ask it for the xml: 
namespace decl.
  +                             
handle=dtm.getHandleOfNode(((org.w3c.dom.Attr)node).getOwnerElement());
  +                             
handle=dtm.getAttributeNode(handle,node.getNamespaceURI(),node.getLocalName());
  +      }
  +      else
  +                             handle = ((DOM2DTM)dtm).getHandleOfNode(node);
   
         if(DTM.NULL == handle)
           throw new 
RuntimeException(XSLMessages.createMessage(XSLTErrorResources.ER_COULD_NOT_RESOLVE_NODE,
 null)); //"Could not resolve the node to a handle!");
  @@ -644,7 +672,7 @@
   
     /**
      * Given a DTM, find the ID number in the DTM tables which addresses
  -   * the start of the document. If extended addressing is in use, other
  +   * the start of the document. If overflow addressing is in use, other
      * DTM IDs may also be assigned to this DTM.
      *
      * @param dtm The DTM which (hopefully) contains this node.
  
  
  
  1.25      +11 -3     
xml-xalan/java/src/org/apache/xml/dtm/ref/dom2dtm/DOM2DTM.java
  
  Index: DOM2DTM.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xml/dtm/ref/dom2dtm/DOM2DTM.java,v
  retrieving revision 1.24
  retrieving revision 1.25
  diff -u -r1.24 -r1.25
  --- DOM2DTM.java      2001/11/29 15:45:52     1.24
  +++ DOM2DTM.java      2001/11/29 16:30:47     1.25
  @@ -797,9 +797,16 @@
         while (DTM.NULL != (identity = getNextNodeIdentity(identity)))
         {
           // Assume this can not be null.
  -        type = getNodeType(identity);
  +        type = _type(identity);
   
  -        if (type == DTM.ATTRIBUTE_NODE)
  +                             // %REVIEW%
  +                             // Should namespace nodes be retrievable 
DOM-style as attrs?
  +                             // If not we need a separate function... which 
may be desirable
  +                             // architecturally, but which is ugly from a 
code point of view.
  +                             // (If we REALLY insist on it, this code should 
become a subroutine
  +                             // of both -- retrieve the node, then test if 
the type matches
  +                             // what you're looking for.)
  +        if (type == DTM.ATTRIBUTE_NODE || type==DTM.NAMESPACE_NODE)
           {
             Node node = lookupNode(identity);
             String nodeuri = node.getNamespaceURI();
  @@ -812,7 +819,8 @@
             if (nodeuri.equals(namespaceURI) && name.equals(nodelocalname))
               return makeNodeHandle(identity);
           }
  -        else if (DTM.NAMESPACE_NODE != type)
  +                             
  +        else // if (DTM.NAMESPACE_NODE != type)
           {
             break;
           }
  
  
  
  1.14      +11 -2     xml-xalan/java/src/org/apache/xpath/XPathAPI.java
  
  Index: XPathAPI.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/XPathAPI.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- XPathAPI.java     2001/06/22 04:36:09     1.13
  +++ XPathAPI.java     2001/11/29 16:30:47     1.14
  @@ -82,8 +82,17 @@
    * created for each evaluation.  A faster way is to precompile the
    * XPaths using the low-level API, and then just use the XPaths
    * over and over.
  - * @see <a href="http://www.w3.org/TR/xpath";>XPath Specification</a>
  - */
  + *
  + * NOTE: In particular, each call to this method will create a new
  + * XPathContext, a new DTMManager... and thus a new DTM. That's very
  + * safe, since it guarantees that you're always processing against a
  + * fully up-to-date view of your document. But it's also portentially
  + * very expensive, since you're rebuilding the DTM every time. You should
  + * consider using an instance of CachedXPathAPI rather than these static
  + * methods.
  + *
  + * @see <a href="http://www.w3.org/TR/xpath";>XPath Specification</a> 
  + * */
   public class XPathAPI
   {
   
  
  
  
  1.1                  xml-xalan/java/src/org/apache/xpath/CachedXPathAPI.java
  
  Index: CachedXPathAPI.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:  
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Xalan" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written 
   *    permission, please contact [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation and was
   * originally based on software copyright (c) 1999, Lotus
   * Development Corporation., http://www.lotus.com.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.xpath;
  
  import javax.xml.transform.TransformerException;
  
  import org.w3c.dom.Node;
  import org.w3c.dom.Document;
  import org.w3c.dom.traversal.NodeIterator;
  import org.w3c.dom.NodeList;
  
  import org.apache.xpath.XPathContext;
  import org.apache.xpath.XPath;
  import org.apache.xpath.compiler.XPathParser;
  import org.apache.xpath.XPathContext;
  import org.apache.xml.utils.PrefixResolverDefault;
  import org.apache.xml.utils.PrefixResolver;
  import org.apache.xpath.objects.XObject;
  import org.apache.xml.dtm.DTM;
  import org.apache.xml.dtm.ref.DTMNodeIterator;
  import org.apache.xml.dtm.ref.DTMNodeList;
  import org.apache.xml.dtm.ref.DTMManagerDefault;
  
  /**
   * The methods in this class are convenience methods into the
   * low-level XPath API.
   *
   * These functions tend to be a little slow, since a number of objects must be
   * created for each evaluation.  A faster way is to precompile the
   * XPaths using the low-level API, and then just use the XPaths
   * over and over.
   *
   * This is an alternative for the old XPathAPI class, which provided
   * static methods for the purpose but had the drawback of
   * instantiating a new XPathContext (and thus building a new DTMManager,
   * and new DTMs) each time it was called. XPathAPIObject instead retains
   * its context as long as the object persists, reusing the DTMs. This
   * does have a downside: if you've changed your source document, you should
   * obtain a new XPathAPIObject to continue searching it, since trying to use
   * the old DTMs will probably yield bad results or malfunction outright... and
   * the cached DTMs may consume memory until this object and its context are
   * returned to the heap. Essentially, it's the caller's responsibility to
   * decide when to discard the cache.
   *
   * @see <a href="http://www.w3.org/TR/xpath";>XPath Specification</a>
   * */
  public class CachedXPathAPI
  {
    /** XPathContext, and thus DTMManager and DTMs, persists through multiple
        calls to this object.
    */
    XPathContext xpathSupport = new XPathContext();
  
    /**
     * Use an XPath string to select a single node. XPath namespace
     * prefixes are resolved from the context node, which may not
     * be what you want (see the next method).
     *
     * @param contextNode The node to start searching from.
     * @param str A valid XPath string.
     * @return The first node found that matches the XPath, or null.
     *
     * @throws TransformerException
     */
    public  Node selectSingleNode(Node contextNode, String str)
            throws TransformerException
    {
      return selectSingleNode(contextNode, str, contextNode);
    }
  
    /**
     * Use an XPath string to select a single node.
     * XPath namespace prefixes are resolved from the namespaceNode.
     *
     * @param contextNode The node to start searching from.
     * @param str A valid XPath string.
     * @param namespaceNode The node from which prefixes in the XPath will be 
resolved to namespaces.
     * @return The first node found that matches the XPath, or null.
     *
     * @throws TransformerException
     */
    public  Node selectSingleNode(
            Node contextNode, String str, Node namespaceNode)
              throws TransformerException
    {
  
      // Have the XObject return its result as a NodeSetDTM.
      NodeIterator nl = selectNodeIterator(contextNode, str, namespaceNode);
  
      // Return the first node, or null
      return nl.nextNode();
    }
  
    /**
     *  Use an XPath string to select a nodelist.
     *  XPath namespace prefixes are resolved from the contextNode.
     *
     *  @param contextNode The node to start searching from.
     *  @param str A valid XPath string.
     *  @return A NodeIterator, should never be null.
     *
     * @throws TransformerException
     */
    public  NodeIterator selectNodeIterator(Node contextNode, String str)
            throws TransformerException
    {
      return selectNodeIterator(contextNode, str, contextNode);
    }
  
    /**
     *  Use an XPath string to select a nodelist.
     *  XPath namespace prefixes are resolved from the namespaceNode.
     *
     *  @param contextNode The node to start searching from.
     *  @param str A valid XPath string.
     *  @param namespaceNode The node from which prefixes in the XPath will be 
resolved to namespaces.
     *  @return A NodeIterator, should never be null.
     *
     * @throws TransformerException
     */
    public  NodeIterator selectNodeIterator(
            Node contextNode, String str, Node namespaceNode)
              throws TransformerException
    {
  
      // Execute the XPath, and have it return the result
      XObject list = eval(contextNode, str, namespaceNode);
  
      // Have the XObject return its result as a NodeSetDTM.                
      return list.nodeset();
    }
  
    /**
     *  Use an XPath string to select a nodelist.
     *  XPath namespace prefixes are resolved from the contextNode.
     *
     *  @param contextNode The node to start searching from.
     *  @param str A valid XPath string.
     *  @return A NodeIterator, should never be null.
     *
     * @throws TransformerException
     */
    public  NodeList selectNodeList(Node contextNode, String str)
            throws TransformerException
    {
      return selectNodeList(contextNode, str, contextNode);
    }
  
    /**
     *  Use an XPath string to select a nodelist.
     *  XPath namespace prefixes are resolved from the namespaceNode.
     *
     *  @param contextNode The node to start searching from.
     *  @param str A valid XPath string.
     *  @param namespaceNode The node from which prefixes in the XPath will be 
resolved to namespaces.
     *  @return A NodeIterator, should never be null.
     *
     * @throws TransformerException
     */
    public  NodeList selectNodeList(
            Node contextNode, String str, Node namespaceNode)
              throws TransformerException
    {
  
      // Execute the XPath, and have it return the result
      XObject list = eval(contextNode, str, namespaceNode);
  
      // Return a NodeList.
      return list.nodelist();
    }
  
    /**
     *  Evaluate XPath string to an XObject.  Using this method,
     *  XPath namespace prefixes will be resolved from the namespaceNode.
     *  @param contextNode The node to start searching from.
     *  @param str A valid XPath string.
     *  @param namespaceNode The node from which prefixes in the XPath will be 
resolved to namespaces.
     *  @return An XObject, which can be used to obtain a string, number, 
nodelist, etc, should never be null.
     *  @see org.apache.xpath.objects.XObject
     *  @see org.apache.xpath.objects.XNull
     *  @see org.apache.xpath.objects.XBoolean
     *  @see org.apache.xpath.objects.XNumber
     *  @see org.apache.xpath.objects.XString
     *  @see org.apache.xpath.objects.XRTreeFrag
     *
     * @throws TransformerException
     */
    public  XObject eval(Node contextNode, String str)
            throws TransformerException
    {
      return eval(contextNode, str, contextNode);
    }
  
    /**
     *  Evaluate XPath string to an XObject. 
     *  XPath namespace prefixes are resolved from the namespaceNode.
     *  The implementation of this is a little slow, since it creates
     *  a number of objects each time it is called.  This could be optimized
     *  to keep the same objects around, but then thread-safety issues would 
arise.
     *
     *  @param contextNode The node to start searching from.
     *  @param str A valid XPath string.
     *  @param namespaceNode The node from which prefixes in the XPath will be 
resolved to namespaces.
     *  @return An XObject, which can be used to obtain a string, number, 
nodelist, etc, should never be null.
     *  @see org.apache.xpath.objects.XObject
     *  @see org.apache.xpath.objects.XNull
     *  @see org.apache.xpath.objects.XBoolean
     *  @see org.apache.xpath.objects.XNumber
     *  @see org.apache.xpath.objects.XString
     *  @see org.apache.xpath.objects.XRTreeFrag
     *
     * @throws TransformerException
     */
    public  XObject eval(Node contextNode, String str, Node namespaceNode)
            throws TransformerException
    {
  
      // Since we don't have a XML Parser involved here, install some default 
support
      // for things like namespaces, etc.
      // (Changed from: XPathContext xpathSupport = new XPathContext();
      //    because XPathContext is weak in a number of areas... perhaps
      //    XPathContext should be done away with.)
  
      // Create an object to resolve namespace prefixes.
      // XPath namespaces are resolved from the input context node's document 
element
      // if it is a root node, or else the current context node (for lack of a 
better
      // resolution space, given the simplicity of this sample code).
      PrefixResolverDefault prefixResolver = new PrefixResolverDefault(
        (namespaceNode.getNodeType() == Node.DOCUMENT_NODE)
        ? ((Document) namespaceNode).getDocumentElement() : namespaceNode);
  
      // Create the XPath object.
      XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null);
  
      // Execute the XPath, and have it return the result
      // return xpath.execute(xpathSupport, contextNode, prefixResolver);
      int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode);
  
      return xpath.execute(xpathSupport, ctxtNode, prefixResolver);
    }
  
    /**
     *   Evaluate XPath string to an XObject.
     *   XPath namespace prefixes are resolved from the namespaceNode.
     *   The implementation of this is a little slow, since it creates
     *   a number of objects each time it is called.  This could be optimized
     *   to keep the same objects around, but then thread-safety issues would 
arise.
     *
     *   @param contextNode The node to start searching from.
     *   @param str A valid XPath string.
     *   @param namespaceNode The node from which prefixes in the XPath will be 
resolved to namespaces.
     *   @param prefixResolver Will be called if the parser encounters namespace
     *                         prefixes, to resolve the prefixes to URLs.
     *   @return An XObject, which can be used to obtain a string, number, 
nodelist, etc, should never be null.
     *   @see org.apache.xpath.objects.XObject
     *   @see org.apache.xpath.objects.XNull
     *   @see org.apache.xpath.objects.XBoolean
     *   @see org.apache.xpath.objects.XNumber
     *   @see org.apache.xpath.objects.XString
     *   @see org.apache.xpath.objects.XRTreeFrag
     *
     * @throws TransformerException
     */
    public  XObject eval(
            Node contextNode, String str, PrefixResolver prefixResolver)
              throws TransformerException
    {
  
      // Since we don't have a XML Parser involved here, install some default 
support
      // for things like namespaces, etc.
      // (Changed from: XPathContext xpathSupport = new XPathContext();
      //    because XPathContext is weak in a number of areas... perhaps
      //    XPathContext should be done away with.)
      // Create the XPath object.
      XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null);
  
      // Execute the XPath, and have it return the result
      XPathContext xpathSupport = new XPathContext();
      int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode);
  
      return xpath.execute(xpathSupport, ctxtNode, prefixResolver);
    }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to