使用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。
具体步骤:
- 添加依赖:如果用Maven,把这段依赖加到你的
pom.xml里(版本用最新稳定版就行):
用Gradle的话对应调整即可。<dependency> <groupId>net.sf.saxon</groupId> <artifactId>Saxon-HE</artifactId> <version>12.4</version> </dependency> - 修改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




