很早很久以前写过一篇 在 xslt 调用 java 方法的日志 XSLT 调用 Java 的类方法, 其中介绍是使用 org.apache.xalan.processor.TransformerFactoryImpl 实现的例子,JDK 本身就是用这个的。但是在 Tomcat 环境下,它有它自己的 XSLT 默认实现是 net.sf.saxon.TransformerFactoryImpl,这时候 XSLT 中的内容略有不同,而且显示更简便一些。
这么说吧, xalan 支持以下两种调用 java 方法的方式,而 saxon 只认得第二种
1. 声明到包,调用时带上类名
1 2 3 4 5 6 7 8 9 10 |
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:java="cc.unmi.commons" exclude-result-prefixes="java"> <xsl:output method="xml"/> <xsl:template match="user/name"> <li><xsl:value-of select='java:XsltFunctions.replace(.)'/></li> </xsl:template> </xsl:stylesheet> |
2. 声明到类,直接用方法名
1 2 3 4 5 6 7 8 9 10 |
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:java="cc.unmi.commons.XsltFunctions" exclude-result-prefixes="java"> <xsl:output method="xml"/> <xsl:template match="user/name"> <li><xsl:value-of select='java:replace(.)'/></li> </xsl:template> </xsl:stylesheet> |
显然第二种方式写起来要简便些,省却了每次调用时输入类名,如果会用到多个类中的方法就多写个 Namespace xmlns:proc="cc.unmi.common.ProcFunctions" 就行,用 proc:foo() 来调用。
此处省略了 cc.unmi.commons.XsltFunctions.replace(String src) 实现,可参考 在 xslt 调用 java 方法的日志 XSLT 调用 Java 的类方法。
如果用下面的方法结合第一个 xslt 的写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public static void transfer() throws Exception{ Source xmlSource = new StreamSource("example.xml"); Source xsltSource = new StreamSource("example.xslt"); System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl"); TransformerFactory transfact = TransformerFactory.newInstance(); StringWriter sw = new StringWriter(); Result result = new StreamResult(sw); Transformer trans = transfact.newTransformer(xsltSource); trans.transform(xmlSource, result); System.out.println(sw.toString()); } |
会收到类似这样的错误:
Error at xsl:value-of on line 8 of :
XPST0003: XPath syntax error at char 62 on line 8 in {.......}:
Cannot find a matching 1-argument function named
{cc.unmi.commons}XslFunctions.replace()
应用第 2 个 xslt 内容则可通过,或者把实现改成
System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");
则可兼容并蓄。
如果构造 TransformerFactory 实例时指定实现类则更具灵活性,即两种实现能较好的共存。
1 |
TransformerFactory transfact = TransformerFactory.newInstance("YOUR TransformerFactory implementation HERE", classLoader); |
再补充一点,用 xalan 时,XSLT 中 XPath 选取的节点类型是 org.w3c.dom.Node,这个比较好处理,而用 saxon 时,XPath 选取的节点类型则是 net.sf.saxon.om.NodeInfo, 它和 w3c 的 Node 摊不上一点关系,也只有它的 getStringValue() 较有用处。
本文链接 https://yanbin.blog/xslt-call-java-functions-tomcat-env/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
[...] Unmi 很早很久以前写过一篇 在 xslt 调用 java 方法的日志 XSLT 调用 Java 的类方法, [...]