问题
I am using ServiceMix 4.5.3 which includes Camel 2.10.7 and I am able to make XSLT 2.0 transformations with the Saxon library using the option endpoint like this:
...
to("xslt:stylesheet.xsl?transformerFactoryClass=net.sf.saxon.TransformerFactoryImpl")
...
However when I try to use the xpath function like this:
private Namespaces ourNS = new Namespaces("myns",
"urn:com:company:domain:namespace:myns/1");
// ... some code ...
// Make a predicate to filter according a header :
// The code attribute looks like: urn:phone:apple:iphone:4s
Predicate isNotSamePhoneBrand = PredicateBuilder.isNotEqualTo(
xpath("tokenize(/myns:Phone/@code, ':')[3]").namespaces(ourNS),
header("PhoneBrand"));
If I execute the above code it says the tokenize() function is unknown. I guess it is because it still uses xalan (xpath 1.0) instead Saxon.
I also tried as well to append the .saxon() as in the Camel documentation
Predicate isNotSamePhoneBrand = PredicateBuilder.isNotEqualTo(
xpath("tokenize(/myns:Phone/@code, ':')[3]").namespaces(ourNS).saxon(),
header("PhoneBrand"));
But it makes an error that he cannot find the Saxon implementation factory:
Caused by: javax.xml.xpath.XPathFactoryConfigurationException: No XPathFctory implementation found for the object model: http://saxon.sf.net/jaxp/xpath/om
In my OSGI context I verified that both camel-saxon
and Apache ServiceMix :: Bundles :: saxon9he (9.3.0.11_2)
are deployed.
We are planning to upgrade to ServiceMix 5 soon but I do not know if this problem is still there or not, a solution for the version 4.5.3 would be better for me.
回答1:
In Saxon 9.6 we removed the services file that registered Saxon as an implementation of the JAXP XPathFactory interface. It still implements that interface, it just doesn't have a services file in the JAR file manifest that says so. There's a long history behind this, but there are basically two main reasons: (a) incompatibility between JDK releases making it impossible to produce a services file that works from JDK 5 to JDK 8 inclusive, and (b) merely putting Saxon on the classpath was causing applications to break if they were not written or tested to work with XPath 2.0.
I guess there's a workaround by adding the services file to the SAXON Jar file manifest yourself (you can copy it from the 9.5 release).
回答2:
Finally I found a working solution for the camel route:
As the .saxon() was without effect on my route, I decided to look another way and I found there is a specific option to override the Xpath factory like this:
.factory(new net.sf.saxon.xpath.XPathFactoryImpl())
After that I had to force the conversion of the result of the Xpath into a String with .resultType(String.class)
.
The full predicate will looks like this:
Predicate isNotSamePhoneBrand = PredicateBuilder.isNotEqualTo(
xpath("tokenize(/myns:Phone/@code, ':')[3]").namespaces(ourNS)
.factory(new net.sf.saxon.xpath.XPathFactoryImpl()).resultType(String.class),
header("PhoneBrand"));
and now the tokenize function (xpath 2.0) is very well recognized.
I found that I have to do the same thing with the instantiation of the factory implementation when I use it in a camel Processor like this:
net.sf.saxon.xpath.XPathFactoryImpl factory = new net.sf.saxon.xpath.XPathFactoryImpl();
XPath xpath = factory.newXPath();
NodeList channels = (NodeList) xpath.evaluate(
"//*:Channels/*:Channel/text()",
body, XPathConstants.NODESET);
This is not dynamic but I want to force the usage of Saxon everywhere then this solution fit our needs.
来源:https://stackoverflow.com/questions/28322554/apache-camel-xpath-2-0-with-saxon-does-not-look-to-work-in-routebuilder-predic