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]