基于子节点Category/ID去重Total节点并合计指定字段的XSLT实现问题
需求说明
以//Category/ID作为唯一值,对其父节点Total进行去重,删除重复的Total节点,将被删除节点的TotalAmount、Tax字段值累加至保留的对应同ID节点中。例如示例中Category/ID为"S"的两个Total节点需合并,TotalAmount合计为250.00、Tax合计为40.00。原有编写的XSLT无法正常实现该功能。
输入示例
<root> <Total> <TotalAmount currencyID="EUR">100.00</TotalAmount> <Tax currencyID="EUR">20.00</Tax> <Category> <ID>S</ID> <Percent>21.000</Percent> <Description> <ID>Note</ID> </Description> </Category> </Total> <Total> <TotalAmount currencyID="EUR">150.00</TotalAmount> <Tax currencyID="EUR">20.00</Tax> <Category> <ID>S</ID> <Percent>21.000</Percent> <Description> <ID>Note</ID> </Description> </Category> </Total> <Total> <TotalAmount currencyID="EUR">200.00</TotalAmount> <Tax currencyID="EUR">0</Tax> <Category> <ID>O</ID> <Percent>0</Percent> <Description> <ID>Note</ID> </Description> </Category> </Total> </root>
原有问题XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:key name="kByP" match="Category" use="ID"/> <xsl:template match="node()|@*"> <xsl:param name="pNewValue"/> <xsl:copy> <xsl:apply-templates select="node()|@*"> <xsl:with-param name="pNewValue" select="$pNewValue"/> </xsl:apply-templates> </xsl:copy> </xsl:template> <xsl:template match= "Category[generate-id() = generate-id(key('kByP', ID)[1]) ]"> <xsl:copy> <xsl:apply-templates select="node()|@*"> <xsl:with-param name="pNewValue" select= "sum(key('kByP', ID)/TotalAmount)"/> </xsl:apply-templates> </xsl:copy> </xsl:template> <xsl:template match="Total"/> <xsl:template match="TotalAmount/text()"> <xsl:param name="pNewValue"/> <xsl:value-of select="$pNewValue"/> </xsl:template> </xsl:stylesheet>
期望输出
<root> <Total> <TotalAmount currencyID="EUR">250.00</TotalAmount> <Tax currencyID="EUR">40.00</Tax> <Category> <ID>S</ID> <Percent>21.000</Percent> <Description> <ID>Note</ID> </Description> </Category> </Total> <Total> <TotalAmount currencyID="EUR">200.00</TotalAmount> <Tax currencyID="EUR">0</Tax> <Category> <ID>O</ID> <Percent>0</Percent> <Description> <ID>Note</ID> </Description> </Category> </Total> </root>
修复方案
原有代码的核心问题有三个:
- 分组key匹配的是Category节点,但计算金额时错误尝试直接从Category节点下找TotalAmount,实际TotalAmount是Category的兄弟节点,父节点为Total
- 直接匹配所有Total节点输出空,导致没有输出Total结构
- 只做了TotalAmount的累加逻辑,没有处理Tax字段的累加
以下是修复后的XSLT代码:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <!-- 按Total下的Category/ID对Total节点分组 --> <xsl:key name="totalByCatId" match="Total" use="Category/ID"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <!-- 只处理每个分组的第一个Total节点 --> <xsl:template match="Total[generate-id() = generate-id(key('totalByCatId', Category/ID)[1])]"> <xsl:copy> <!-- 复制TotalAmount,替换值为同分组所有Total的TotalAmount总和 --> <TotalAmount currencyID="{TotalAmount/@currencyID}"> <xsl:value-of select="sum(key('totalByCatId', Category/ID)/TotalAmount)"/> </TotalAmount> <!-- 复制Tax,替换值为同分组所有Total的Tax总和 --> <Tax currencyID="{Tax/@currencyID}"> <xsl:value-of select="sum(key('totalByCatId', Category/ID)/Tax)"/> </Tax> <!-- 原样复制Category节点 --> <xsl:apply-templates select="Category"/> </xsl:copy> </xsl:template> <!-- 跳过同分组的其他重复Total节点 --> <xsl:template match="Total[generate-id() != generate-id(key('totalByCatId', Category/ID)[1])]"/> </xsl:stylesheet>
该代码使用Muenchian分组法对Total节点按Category/ID分组,仅保留每个分组的第一个Total节点,将同分组所有节点的TotalAmount和Tax分别累加后写入保留节点,其余结构完全保留,输出结果与预期一致。
内容的提问来源于stack exchange,提问作者keeskroket
相关产品推荐
相关产品推荐

