Apache Camel Xpath 2.0 with Saxon does not look to work in RouteBuilder / Predicates

南楼画角 提交于 2019-12-21 22:23:22

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!