XSLT 调用 Java 的类方法 -- Tomcat 环境

很早很久以前写过一篇 在 xslt 调用 java 方法的日志 XSLT 调用 Java 的类方法, 其中介绍是使用 org.apache.xalan.processor.TransformerFactoryImpl 实现的例子,JDK 本身就是用这个的。但是在 Tomcat 环境下,它有它自己的 XSLT 默认实现是 net.sf.saxon.TransformerFactoryImpl, 这时候 XSLT 中的内容略有不同,而且显示更简便一些。


这么说吧, xalan 支持以下两种调用 java 方法的方式,而 saxon 只认得第二种

1. 声明到包,调用时带上类名
 1<?xml version="1.0" encoding="UTF-8"?>
 2<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 3    xmlns:java="cc.unmi.commons" exclude-result-prefixes="java">
 4
 5    <xsl:output method="xml"/>
 6
 7    <xsl:template match="user/name">
 8        <li><xsl:value-of select='java:XsltFunctions.replace(.)'/></li>
 9    </xsl:template>
10</xsl:stylesheet>

2. 声明到类,直接用方法名
 1<?xml version="1.0" encoding="UTF-8"?>
 2<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 3    xmlns:java="cc.unmi.commons.XsltFunctions" exclude-result-prefixes="java">
 4
 5    <xsl:output method="xml"/>
 6
 7    <xsl:template match="user/name">
 8        <li><xsl:value-of select='java:replace(.)'/></li>
 9    </xsl:template>
10</xsl:stylesheet>

显然第二种方式写起来要简便些,省却了每次调用时输入类名,如果会用到多个类中的方法就多写个 Namespace  xmlns:proc="cc.unmi.common.ProcFunctions" 就行,用 proc:foo() 来调用。

此处省略了 cc.unmi.commons.XsltFunctions.replace(String src) 实现,可参考 在 xslt 调用 java 方法的日志 XSLT 调用 Java 的类方法

如果用下面的方法结合第一个 xslt 的写法
 1    public static void transfer() throws Exception{
 2        Source xmlSource = new StreamSource("example.xml");
 3        Source xsltSource = new StreamSource("example.xslt");
 4
 5        System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl");
 6        TransformerFactory transfact = TransformerFactory.newInstance();
 7
 8        StringWriter sw = new StringWriter();
 9        Result result = new StreamResult(sw);
10
11        Transformer trans = transfact.newTransformer(xsltSource);
12        trans.transform(xmlSource, result);
13
14        System.out.println(sw.toString());
15    }

会收到类似这样的错误:

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 实例时指定实现类则更具灵活性,即两种实现能较好的共存。
1TransformerFactory transfact = TransformerFactory.newInstance("YOUR TransformerFactory
2    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's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。