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.
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).
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