Re: XPathAPI(node, xpathStr) & XPathContext.getDTMHandleFromNode(node)
slow
David Portabella wrote:
I am now using the low-level XPath API as follows:
XPathContext xpathSupport = new XPathContext();
PrefixResolverDefault prefixResolver = new
PrefixResolverDefault(document);
XPath xpath = new XPath(xpathStr, null, prefixResolver,
XPath.SELECT, null);
and then, for each node:
int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode);
XObject object = xpath.execute(xpathSupport, node,
prefixResolver);
It gets a bit better, but still, after using over and over again on
several nodes, it gets slower and slower.
I think that the problem is that
XPathContext.getDTMHandleFromNode(child) does not free memory.
It seems to me that Xalan holds all the references to the DTM nodes it
creates (possibly in XPathContext, or DTMManager instance). I'm not
very familiar with Xalan API, nor its internals, but I came to that
conclusion after some experimenting with your example code under Java SE
embedded version of Xalan (I don't know which particular versions of
Xalan each Java embeds).
I tried to remove that DTM references from context as follows:
DTMManager dtmManager = xpathSupport.getDTMManager();
DTM dtm = dtmManager.getDTM(ctxtNode);
dtmManager.release(dtm, true);
But it seems that all DTM references released that way are still
referenced somewhere (possibly in per document context). As the result,
your example performs even slower with that.
However, the above seems to be handy when used for each child node
separately from the original DOM document. i.e. used for the node's
clone referred to that way:
int ctxtNode =
xpathSupport.getDTMHandleFromNode(child.cloneNode(true));
Without releasing the clone's DTM handle, the example very quickly ends
with OutOfMemoryError. But when both the above changes are used, xpath
performs equally fast for each child's clone created in the loop.
Of course, the above solution will work correctly as long as your xpath
expression is not referencing any data of the child's parent node (nor
any data of some other nodes not within its subtree). There are
possibly some other limitations caused by this trick, which I can't come
up with now. But in your particular example, it seems to work fast and
properly.
For those who'd like to check that with Sun's Java 5 and 6 internally
embedded version of Xalan, enough is to replace the following two imports:
import org.apache.xpath.*;
import org.apache.xml.utils.*;
with:
import com.sun.org.apache.xml.internal.utils.*;
import com.sun.org.apache.xpath.internal.*;
import com.sun.org.apache.xml.internal.dtm.*;
Is it possible to solve this problem without discarding xalan?
Hope so. Let us know if the above solves your problem.
piotr