如何在XSLT 1.0中按节点值总和生成连续数字并分页?
问题描述
给定如下XML:第一个line节点(ref=1)下所有name元素值总和为5(2+3),第二个line节点(ref=2)总和为3。要求为每个line生成从1到对应总和的连续数字,同时按每个name的值生成单独页面,总计8页。现有XSLT 1.0代码无法实现预期效果,需修正。
预期输出
line 1 number 1 number 2 number 3 number 4 number 5 line 2 number 1 number 2 number 3
XML输入
<?xml version="1.0" encoding="UTF-8"?> <root parent="a"> <line ref="1"> <child line="1"> <name id="school">2</name> </child> <child line="2"> <name id="school">3</name> </child> </line> <line ref="2"> <child line="1"> <name id="school">1</name> </child> <child line="2"> <name id="school">2</name> </child> </line> </root>
现有XSLT的核心问题
- 数字生成逻辑错误:使用
(//node())[position() <= $pack]遍历XML节点而非生成指定数量的连续数字,完全偏离需求。 - 未按line分组计算总和:仅按单个
child的name值重复输出,未计算每个line的总和并生成连续序列。 - 分页控制混乱:分页标记未与
name的数量正确绑定,无法实现每个name对应单独页面的要求。
修正后的XSLT 1.0代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:fo="http://www.w3.org/1999/XSL/Format"> <xsl:decimal-format name="generalFormat" grouping-separator="," decimal-separator="." /> <!-- 主模板:生成FO根结构并遍历所有line节点 --> <xsl:template match="/"> <fo:root> <fo:layout-master-set> <fo:simple-page-master master-name="ManufacturLabelSize" page-height="100mm" page-width="100mm"> <fo:region-body margin-top="15mm" /> </fo:simple-page-master> <fo:page-sequence-master master-name="ManufacturLabelSize-portrait"> <fo:repeatable-page-master-alternatives> <fo:conditional-page-master-reference master-reference="ManufacturLabelSize" /> </fo:repeatable-page-master-alternatives> </fo:page-sequence-master> </fo:layout-master-set> <xsl:apply-templates select="root/line" /> </fo:root> </xsl:template> <!-- 处理单个line节点:生成line总和序列 + 每个child的单独页面 --> <xsl:template match="line"> <!-- 生成当前line的总和数字序列 --> <fo:page-sequence master-reference="ManufacturLabelSize-portrait"> <fo:flow flow-name="xsl-region-body"> <fo:block>line <xsl:value-of select="@ref" /></fo:block> <xsl:variable name="total" select="sum(child/name[@id='school'])" /> <xsl:call-template name="generate-numbers"> <xsl:with-param name="current" select="1" /> <xsl:with-param name="max" select="$total" /> </xsl:call-template> </fo:flow> </fo:page-sequence> <!-- 为每个child生成单独页面 --> <xsl:for-each select="child"> <xsl:variable name="pack" select="name[@id='school']" /> <fo:page-sequence master-reference="ManufacturLabelSize-portrait"> <fo:flow flow-name="xsl-region-body"> <fo:block>child line <xsl:value-of select="@line" /></fo:block> <xsl:call-template name="generate-numbers"> <xsl:with-param name="current" select="1" /> <xsl:with-param name="max" select="$pack" /> </xsl:call-template> </fo:flow> </fo:page-sequence> </xsl:for-each> </xsl:template> <!-- 递归模板:生成从current到max的连续数字 --> <xsl:template name="generate-numbers"> <xsl:param name="current" /> <xsl:param name="max" /> <xsl:if test="$current <= $max"> <fo:block>number <xsl:value-of select="$current" /></fo:block> <xsl:call-template name="generate-numbers"> <xsl:with-param name="current" select="$current + 1" /> <xsl:with-param name="max" select="$max" /> </xsl:call-template> </xsl:if> </xsl:template> </xsl:stylesheet>
代码说明
- 主模板:初始化FO布局结构,遍历所有
line节点进行处理。 - line处理逻辑:
- 计算当前
line下name值的总和,调用递归模板生成1到总和的连续数字。 - 遍历每个
child,根据其name的值生成单独页面,同样通过递归模板生成对应数量的数字。
- 计算当前
- 递归数字生成:利用XSLT 1.0的递归特性实现连续数字序列生成,这是该版本下生成序列的标准方案。
- 页面布局简化:统一页面模板,无需区分首页和后续页面,减少冗余配置。
内容的提问来源于stack exchange,提问作者Akash
相关产品推荐
相关产品推荐

