我正在使用包含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版本的解决方案对我来说会更好。
答案 0 :(得分:3)
在Saxon 9.6中,我们删除了将Saxon注册为JAXP XPathFactory接口实现的服务文件。它仍然实现了该接口,它只是在JAR文件清单中没有一个服务文件。这背后有很长的历史,但基本上有两个主要原因:(a)JDK版本之间的不兼容性使得无法生成从JDK 5到JDK 8(包括JDK)的服务文件,以及(b)仅仅放置Saxon在类路径上导致应用程序在没有编写或测试使用XPath 2.0时会中断。
我想通过自己将服务文件添加到SAXON Jar文件清单中来解决这个问题(您可以从9.5版本中复制它)。
答案 1 :(得分:1)
最后,我找到了骆驼路线的有效解决方案:
由于.saxon()对我的路线没有影响,我决定换另一种方式,我发现有一个特定的选项来覆盖Xpath工厂:
.factory(new net.sf.saxon.xpath.XPathFactoryImpl())
之后我不得不强制将Xpath的结果转换为.resultType(String.class)
的字符串。
完整谓词将如下所示:
Predicate isNotSamePhoneBrand = PredicateBuilder.isNotEqualTo(
xpath("tokenize(/myns:Phone/@code, ':')[3]").namespaces(ourNS)
.factory(new net.sf.saxon.xpath.XPathFactoryImpl()).resultType(String.class),
header("PhoneBrand"));
现在,tokenize函数(xpath 2.0)得到了很好的认可。
我发现当我在像这样的camel处理器中使用它时,我必须对工厂实现的实例化做同样的事情:
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,然后这个解决方案符合我们的需求。