You can use a SAXSource
with XPath using Saxon, but - and this is important - be aware that the underlying implementation will almost certainly still be loading and buffering some or all of the document in memory in order to evaluate the xpath. It probably won't be a full DOM tree (Saxon relies on its own structure called TinyTree
, which supports lazy-loading and various other optimizations), so it's better than using most DOM implementations, but it still involves loading the document into memory. If your concern is memory load for large data sets, it probably won't help you much, and you'd be better off using one of the streaming xpath/xquery options suggested by others.
An implementation of your utility method might look something like this:
import java.io.StringReader;
import javax.xml.namespace.QName;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.sax.SAXSource;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import org.xml.sax.InputSource;
import net.sf.saxon.xpath.XPathFactoryImpl;
public class XPathUtils {
public static Object evaluate(String xpath, String xml, QName returnType)
throws Exception {
SAXParser parser = (SAXParser) SAXParserFactory.newInstance()
.newSAXParser();
InputSource source = new InputSource(new StringReader(xml));
SAXSource saxSource = new SAXSource(parser.getXMLReader(), source);
XPath xPath = new XPathFactoryImpl().newXPath();
return xPath.evaluate(xpath, saxSource, returnType);
}
public static String xpathString(String xpath, String xml)
throws Exception {
return (String) evaluate(xpath, xml, XPathConstants.STRING);
}
public static boolean xpathBool(String xpath, String xml) throws Exception {
return (Boolean) evaluate(xpath, xml, XPathConstants.BOOLEAN);
}
public static Number xpathNumber(String xpath, String xml) throws Exception {
return (Number) evaluate(xpath, xml, XPathConstants.NUMBER);
}
public static void main(String[] args) throws Exception {
System.out.println(xpathString("/root/@id", "<root id='12345'/>"));
}
}
This works because the Saxon XPath
implementation supports SAXSource
as a context for evaluate()
. Be aware that trying this with the built-in Apaache XPath
implementation will throw an exception.