Apache Camel Xpath 2.0 with Saxon 看起来不能在 RouteBuilder / Predicates 中工作
Apache Camel Xpath 2.0 with Saxon does not look to work in RouteBuilder / Predicates
我正在使用包含 Camel 2.10.7 的 ServiceMix 4.5.3,我能够使用像这样的选项端点对 Saxon 库进行 XSLT 2.0 转换:
...
to("xslt:stylesheet.xsl?transformerFactoryClass=net.sf.saxon.TransformerFactoryImpl")
...
然而,当我尝试像这样使用 xpath 函数时:
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"));
如果我执行上面的代码,它说 tokenize() 函数未知。我猜是因为它仍然使用 xalan (xpath 1.0) 而不是 Saxon。
我也尝试像在 Camel 文档中那样附加 .saxon()
Predicate isNotSamePhoneBrand = PredicateBuilder.isNotEqualTo(
xpath("tokenize(/myns:Phone/@code, ':')[3]").namespaces(ourNS).saxon(),
header("PhoneBrand"));
但是报错找不到Saxon实现工厂:
Caused by: javax.xml.xpath.XPathFactoryConfigurationException: No XPathFctory implementation found for the object model: http://saxon.sf.net/jaxp/xpath/om
在我的 OSGI 上下文中,我验证了 camel-saxon
和 Apache ServiceMix :: Bundles :: saxon9he (9.3.0.11_2)
都已部署。
我们计划尽快升级到 ServiceMix 5,但我不知道这个问题是否仍然存在,4.5.3 版本的解决方案对我来说会更好。
在 Saxon 9.6 中,我们删除了将 Saxon 注册为 JAXP XPathFactory 接口实现的服务文件。它仍然实现该接口,只是在 JAR 文件清单中没有这样说明的服务文件。这背后有很长的历史,但基本上有两个主要原因:(a) JDK 版本之间的不兼容性导致无法生成适用于 JDK 5 到 JDK 8 的服务文件包容性,并且 (b) 仅仅将 Saxon 放在类路径中会导致应用程序中断,如果它们没有被编写或测试为与 XPath 2.0 一起工作。
我想有一个解决方法,就是自己将服务文件添加到 SAXON Jar 文件清单中(您可以从 9.5 版本复制它)。
我终于找到了骆驼路线的可行解决方案:
由于 .saxon() 对我的路线没有影响,我决定换一种方式,我发现有一个特定的选项可以像这样覆盖 Xpath 工厂:
.factory(new net.sf.saxon.xpath.XPathFactoryImpl())
之后,我不得不使用 .resultType(String.class)
将 Xpath 的结果强制转换为字符串。
完整的谓词如下所示:
Predicate isNotSamePhoneBrand = PredicateBuilder.isNotEqualTo(
xpath("tokenize(/myns:Phone/@code, ':')[3]").namespaces(ourNS)
.factory(new net.sf.saxon.xpath.XPathFactoryImpl()).resultType(String.class),
header("PhoneBrand"));
现在标记化函数 (xpath 2.0) 得到了很好的认可。
我发现当我在骆驼处理器中使用它时,我必须对工厂实现的实例化做同样的事情:
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);
这不是动态的,但我想在任何地方强制使用 Saxon,这样这个解决方案就符合我们的需要。
我正在使用包含 Camel 2.10.7 的 ServiceMix 4.5.3,我能够使用像这样的选项端点对 Saxon 库进行 XSLT 2.0 转换:
...
to("xslt:stylesheet.xsl?transformerFactoryClass=net.sf.saxon.TransformerFactoryImpl")
...
然而,当我尝试像这样使用 xpath 函数时:
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"));
如果我执行上面的代码,它说 tokenize() 函数未知。我猜是因为它仍然使用 xalan (xpath 1.0) 而不是 Saxon。
我也尝试像在 Camel 文档中那样附加 .saxon()
Predicate isNotSamePhoneBrand = PredicateBuilder.isNotEqualTo(
xpath("tokenize(/myns:Phone/@code, ':')[3]").namespaces(ourNS).saxon(),
header("PhoneBrand"));
但是报错找不到Saxon实现工厂:
Caused by: javax.xml.xpath.XPathFactoryConfigurationException: No XPathFctory implementation found for the object model: http://saxon.sf.net/jaxp/xpath/om
在我的 OSGI 上下文中,我验证了 camel-saxon
和 Apache ServiceMix :: Bundles :: saxon9he (9.3.0.11_2)
都已部署。
我们计划尽快升级到 ServiceMix 5,但我不知道这个问题是否仍然存在,4.5.3 版本的解决方案对我来说会更好。
在 Saxon 9.6 中,我们删除了将 Saxon 注册为 JAXP XPathFactory 接口实现的服务文件。它仍然实现该接口,只是在 JAR 文件清单中没有这样说明的服务文件。这背后有很长的历史,但基本上有两个主要原因:(a) JDK 版本之间的不兼容性导致无法生成适用于 JDK 5 到 JDK 8 的服务文件包容性,并且 (b) 仅仅将 Saxon 放在类路径中会导致应用程序中断,如果它们没有被编写或测试为与 XPath 2.0 一起工作。
我想有一个解决方法,就是自己将服务文件添加到 SAXON Jar 文件清单中(您可以从 9.5 版本复制它)。
我终于找到了骆驼路线的可行解决方案:
由于 .saxon() 对我的路线没有影响,我决定换一种方式,我发现有一个特定的选项可以像这样覆盖 Xpath 工厂:
.factory(new net.sf.saxon.xpath.XPathFactoryImpl())
之后,我不得不使用 .resultType(String.class)
将 Xpath 的结果强制转换为字符串。
完整的谓词如下所示:
Predicate isNotSamePhoneBrand = PredicateBuilder.isNotEqualTo(
xpath("tokenize(/myns:Phone/@code, ':')[3]").namespaces(ourNS)
.factory(new net.sf.saxon.xpath.XPathFactoryImpl()).resultType(String.class),
header("PhoneBrand"));
现在标记化函数 (xpath 2.0) 得到了很好的认可。
我发现当我在骆驼处理器中使用它时,我必须对工厂实现的实例化做同样的事情:
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);
这不是动态的,但我想在任何地方强制使用 Saxon,这样这个解决方案就符合我们的需要。