如何在XSLT聚合求和中获取正确的总计值?
XSLT按report_id和type聚合求和并计算总计值
问题说明
作为XSLT新手,我已经被困数日,试图获取quantity的总计值。目前我能按report_id和type进行聚合求和,并舍弃负的聚合结果(如report_id 222和444),但总计值计算错误:
- 当前输出:
111 A=8; 111 B=4; 333 B=7; 0 - 期望输出:
111 A=8; 111 B=4; 333 B=7; 19
XML数据源
<?xml version="1.0" encoding="UTF-8"?> <root> <report> <report_id>111</report_id> <group> <type>A</type> <quantity>2</quantity> </group> <group> <type>B</type> <quantity>4</quantity> </group> <group> <type>A</type> <quantity>6</quantity> </group> </report> <report> <report_id>222</report_id> <group> <type>A</type> <quantity>-5</quantity> </group> <group> <type>A</type> <quantity>2</quantity> </group> </report> <report> <report_id>333</report_id> <group> <type>B</type> <quantity>7</quantity> </group> </report> <report> <report_id>444</report_id> <group> <type>B</type> <quantity>-12</quantity> </group> </report> </root>
我的XSLT代码(存在问题)
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet exclude-result-prefixes="xsl" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"> <xsl:output method="text" /> <xsl:template match="/root"> <xsl:variable name="total_qty" select="0"/> <xsl:variable name="grand_qty" select="0"/> <xsl:for-each-group select="report/group" group-by="concat(../report_id, '|', type)"> <xsl:variable name="qty" select="sum(current-group()/quantity)"/> <xsl:if test="$qty > 0"> <xsl:variable name="total_qty" select="$qty + $total_qty"/> <xsl:value-of select="concat(../report_id, ' ', type, '=', $total_qty, '; ')"/> <xsl:variable name="grand_qty" select="$grand_qty + $total_qty"/> </xsl:if> </xsl:for-each-group> <xsl:value-of select="$grand_qty"/> </xsl:template> </xsl:stylesheet>
问题原因
XSLT中的变量是不可变的——一旦定义就无法修改。你在for-each-group内部重新定义的$total_qty和$grand_qty是局部变量,和外层同名变量完全无关,所以外层的$grand_qty始终保持初始值0。
修正后的XSLT代码(XSLT 2.0兼容)
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet exclude-result-prefixes="xsl" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:output method="text" /> <xsl:template match="/root"> <!-- 先计算所有有效分组的结果,存储为节点集 --> <xsl:variable name="valid-groups"> <xsl:for-each-group select="report/group" group-by="concat(../report_id, '|', type)"> <xsl:variable name="qty" select="sum(current-group()/quantity)"/> <xsl:if test="$qty > 0"> <group-entry> <report-id><xsl:value-of select="../report_id"/></report-id> <type><xsl:value-of select="type"/></type> <sum><xsl:value-of select="$qty"/></sum> </group-entry> </xsl:if> </xsl:for-each-group> </xsl:variable> <!-- 遍历有效分组输出 --> <xsl:for-each select="$valid-groups/group-entry"> <xsl:value-of select="concat(report-id, ' ', type, '=', sum, '; ')"/> </xsl:for-each> <!-- 计算并输出总计值 --> <xsl:value-of select="sum($valid-groups/group-entry/sum)"/> </xsl:template> </xsl:stylesheet>
代码解释
- 先通过
for-each-group计算所有符合条件(求和结果>0)的分组,将每个分组的report_id、type和求和结果存储到临时节点集$valid-groups中。 - 遍历临时节点集输出每个分组的信息。
- 使用
sum()函数直接对临时节点集中的所有sum节点求和,得到总计值。
内容的提问来源于stack exchange,提问作者Pete
相关产品推荐
相关产品推荐

