Reputation: 658
I have a method for testing
private String getXmlVersion(byte[] xml) throws Exception {
String expression = "//Document/@version";
XPathFactoryImpl xPathFactory = new XPathFactoryImpl();
XPath xPath = xPathFactory.newXPath();
// DocumentBuilder db = new DocumentBuilderFactoryImpl().newDocumentBuilder();
// org.w3c.dom.Document xmlDoc = db.parse(new ByteArrayInputStream(xml));
XPathExpression ex = xPath.compile(expression);
// return "" + ex.evaluate(xmlDoc, XPathConstants.STRING);
return "" + ex.evaluate(new InputSource(new ByteArrayInputStream(xml)), XPathConstants.STRING);
}
I am using net.sf.saxon.dom.DocumentBuilderFactoryImpl
and net.sf.saxon.xpath.XPathFactoryImpl
. This version doesn't pass the test, cos XPath evaluates as empty string. But if I uncomment lines and start to use DocumentBuilder
- XPath evaluates as expected and all tests will be passed.
In documentation I read that...
It is important to note that a compiled XPath expression can only be used with a source document that was built using the same Saxon Configuration.
Seems like when I use both DocumentBuilderFactoryImpl
and XPathFactoryImpl
, their Configuration
is differs, but tests is passed. But what's wrong with a way when I use only XpathFactoryImpl
?
I am using saxon 9.2.0.5.
can anyone help me by example of correct way using Saxon and XPath? Thank you for wasting your time for me and best regards.
EDIT I have tried to use s9api for that and here is a method example
private String getVersion(byte[] xmlData) throws Exception {
Processor proc = new Processor(false);
DocumentBuilder builder = proc.newDocumentBuilder();
XPathCompiler xpc = proc.newXPathCompiler();
xpc.declareNamespace("", "http://namespaceurl.info/ver2/rev2");
XPathSelector selector = xpc.compile("//Document/@version").load();
selector.setContextItem(builder.build(new StreamSource(new ByteArrayInputStream(xmlData))));
XdmItem xdmItem = selector.evaluateSingle();
return xdmItem == null ? "" : xdmItem.getStringValue();
}
This method pass a half of the tests, because it used explicitly defined namespace. But in different versions of documents namespaces is different.
Upvotes: 3
Views: 648
Reputation: 163595
The best way to use Saxon and XPath is to use Saxon's s9api API rather than the JAXP API. There are several advantages to this:
(a) the JAXP API is designed around XPath 1.0 rather than 2.0/3.1
(b) the JAXP API, although it tries to be object-model-neutral, is designed around DOM, while for Saxon, DOM is probably the least efficient tree model of all those supported.
(c) s9api is a lot more usable (type safety, thread safety, binding of namespaces, binding of external variables and functions).
If you do want to use the JAXP XPath API with Saxon, and to run it against a DOM tree, then it can be done.
You haven't said which version of Saxon you are using. The DocumentBuilderFactoryImpl was deprecated in 9.3, and dropped some time before 9.6 (the current release is 9.8).
At this stage it depends a little what you want to do. Do you want to run several XPath expressions against the source tree, or just one? If it's just one, you can supply a StreamSource and let Saxon build the tree in whatever way it considers most efficient. If it's several, then you should build the tree yourself. Does it have to be a DOM tree, given that the DOM is far less efficient than other models (notably than Saxon's own TinyTree). If it does, then you can simply supply a DOMSource to the XPath evaluation. If it doesn't, then build a TinyTree - at which point you are definitely better off using s9api interfaces rather than JAXP.
Upvotes: 1