You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用Java通过XSL从XML生成PDF时遇for-each-group不支持错误

解决XSLT中for-each-group不支持的问题

看起来你踩了Java XSLT处理器版本兼容的坑——这个错误的核心原因很明确:你用的Java默认XSLT处理器(比如Xalan)只支持XSLT 1.0,但你的样式表不仅声明了XSLT 3.0,还用到了XSLT 2.0才引入的<xsl:for-each-group>元素,1.0处理器根本不认识这个元素,所以直接报错了。

给你两个可行的解决方案,按需选择:

方案1:换成支持XSLT 2.0/3.0的处理器(推荐)

Java自带的Xalan处理器是个老古董了,只停留在XSLT 1.0。想要顺畅使用<xsl:for-each-group>这类现代XSLT特性,换成Saxon-HE(免费开源版)就好,它完全支持XSLT 2.0和3.0。

具体步骤:

  1. 添加依赖:如果用Maven,把这段依赖加到你的pom.xml里(版本用最新稳定版就行):
    <dependency>
        <groupId>net.sf.saxon</groupId>
        <artifactId>Saxon-HE</artifactId>
        <version>12.4</version>
    </dependency>
    
    用Gradle的话对应调整即可。
  2. 修改Java代码:把创建TransformerFactory的代码换成Saxon的实现,替代默认的工厂:
    // 替换原来的 TransformerFactory.newInstance()
    TransformerFactory factory = new net.sf.saxon.TransformerFactoryImpl();
    Source xsltSource = new StreamSource(new File("你的样式表路径.xsl"));
    Transformer transformer = factory.newTransformer(xsltSource);
    // 后续生成PDF的逻辑不用改
    

方案2:用XSLT 1.0的方式实现分组(不换处理器)

如果不想换处理器,那得把<xsl:for-each-group>改成XSLT 1.0支持的Muenchian分组法,这是1.0时代实现分组的标准方式。

举个例子,假设你原来的分组代码是这样的:

<xsl:for-each-group select="receipt/item" group-by="@category">
    <h3>分类:<xsl:value-of select="current-grouping-key()"/></h3>
    <xsl:for-each select="current-group()">
        <p><xsl:value-of select="name"/>:<xsl:value-of select="price"/></p>
    </xsl:for-each>
</xsl:for-each-group>

改成XSLT 1.0的写法:

<!-- 先定义分组的键 -->
<xsl:key name="item-by-category" match="receipt/item" use="@category"/>

<!-- 然后遍历每个分组的第一个元素,实现分组 -->
<xsl:for-each select="receipt/item[generate-id() = generate-id(key('item-by-category', @category)[1])]">
    <h3>分类:<xsl:value-of select="@category"/></h3>
    <!-- 遍历当前分组下的所有元素 -->
    <xsl:for-each select="key('item-by-category', @category)">
        <p><xsl:value-of select="name"/>:<xsl:value-of select="price"/></p>
    </xsl:for-each>
</xsl:for-each>

额外提醒

你的样式表输出是HTML,之后还要转成PDF——不管选哪个方案,都要确保后续的PDF生成工具(比如Flying Saucer、iText等)和你用的XSLT处理器兼容,避免出现新的问题。

内容的提问来源于stack exchange,提问作者Karthikeyan

火山引擎 最新活动