XSLT1.0按位置字段分组,实现分组变化时重复打印表头
XSLT 1.0 按客户名称分组并重复打印表头的解决方案
在XSLT 1.0里没法用“循环存变量判断”的方式实现需求——因为XSLT是声明式函数式语言,变量一旦赋值就不可修改,for-each迭代里的变量都是局部独立的,没法跨迭代保留状态。正确的做法是用Muenchian分组法,这是XSLT1.0实现分组的标准方案,具体步骤如下:
1. 定义分组键
在XSLT的顶层(xsl:stylesheet标签下)定义一个key,用来按第8个COL(客户名称)对目标节点分组:
<xsl:key name="group-by-customer" match="GROUP[@ID='1']/GROUP_DATA_ROW" use="COL[8]"/>
match:指定要分组的节点范围——ID为1的GROUP下所有GROUP_DATA_ROWuse:指定分组依据——第8个COL节点的文本值(客户名称)
2. 遍历唯一客户分组
通过key()函数结合generate-id()获取所有唯一的客户分组,再逐个处理每个分组:
<!-- 匹配ID=1的GROUP节点 --> <xsl:template match="GROUP[@ID='1']"> <!-- 筛选出每个客户分组的第一个节点,以此获取所有唯一客户 --> <xsl:for-each select="GROUP_DATA_ROW[generate-id() = generate-id(key('group-by-customer', COL[8])[1])]"> <!-- 可选:按客户名称排序,按需开启 --> <xsl:sort select="COL[8]"/> <!-- 打印当前客户分组的表头 --> <xsl:call-template name="table-header"/> <!-- 输出当前客户对应的所有数据行 --> <xsl:for-each select="key('group-by-customer', COL[8])"> <xsl:call-template name="data-row"/> </xsl:for-each> </xsl:for-each> </xsl:template>
3. 定义表头和数据行模板
把表头、数据行抽成独立模板,方便复用和维护:
<!-- 表头模板,根据你的PDF格式调整FO标签 --> <xsl:template name="table-header"> <fo:table-row> <fo:table-cell><fo:block>序号</fo:block></fo:table-cell> <fo:table-cell><fo:block>订单号</fo:block></fo:table-cell> <!-- 补充你的其他表头列 --> <fo:table-cell><fo:block>客户名称</fo:block></fo:table-cell> <!-- ...其他列 --> </fo:table-row> </xsl:template> <!-- 数据行模板 --> <xsl:template name="data-row"> <fo:table-row> <fo:table-cell><fo:block><xsl:value-of select="COL[1]"/></fo:block></fo:table-cell> <fo:table-cell><fo:block><xsl:value-of select="COL[2]"/></fo:block></fo:table-cell> <fo:table-cell><fo:block><xsl:value-of select="COL[8]"/></fo:block></fo:table-cell> <!-- ...其他列 --> </fo:table-row> </xsl:template>
关键说明
- Muenchian分组的核心是用
generate-id()判断当前节点是否为对应分组的第一个节点,以此筛选出所有唯一分组 - 完全不需要依赖可变变量跟踪状态,符合XSLT的声明式编程逻辑
- 如果需要按客户名称排序,直接在遍历唯一分组时添加
xsl:sort即可
把上述逻辑整合到你现有的XSLT代码中,替换原来的循环判断逻辑即可生效。注意要确保key的match路径和你的源XML结构完全匹配,表头模板要和你期望的PDF格式一致。
内容的提问来源于stack exchange,提问作者Javier Bosque
相关产品推荐
相关产品推荐

