如何基于XML中兄弟节点的唯一ID值对amt节点求和?
问题:基于XML唯一ID分组求和
我需要按data1元素对XML条目分组,再对每个分组内唯一id对应的amt节点求和,而非直接对所有amt值去重求和。目前的XSLT仅对amt的唯一值求和,未考虑id的唯一性,导致结果错误。
输入XML
<?xml version="1.0" encoding="UTF-8"?> <Records> <Entry> <Result> <id>123</id> <amt>80.00</amt> </Result> <data1>KEY</data1> <data2/> <data3/> <dataN/> </Entry> <Entry> <Result> <id>123</id> <amt>80.00</amt> </Result> <data1>KEY</data1> <data2/> <data3/> <dataN/> </Entry> <Entry> <Result> <id>123</id> <amt>80</amt> </Result> <data1>KEY1</data1> <data2/> <data3/> <dataN/> </Entry> <Entry> <Result> <id>ABC</id> <amt>120.25</amt> </Result> <data1>KEY</data1> <data2/> <data3/> <dataN/> </Entry> <Entry> <Result> <id>ABC</id> <amt>120.25</amt> </Result> <data1>KEY</data1> <data2/> <data3/> <dataN/> </Entry> <Entry> <Result> <id>ABC</id> <amt>120.25</amt> </Result> <data1>KEY</data1> <data2/> <data3/> <dataN/> </Entry> <Entry> <Result> <id>ABC</id> <amt>120.25</amt> </Result> <data1>KEY</data1> <data2/> <data3/> <dataN/> </Entry> <Entry> <Result> <id>AB90</id> <amt>75.00</amt> </Result> <data1>KEY2</data1> <data2/> <data3/> <dataN/> </Entry> <Entry> <Result> <id>AB90</id> <amt>75.00</amt> </Result> <data1>KEY2</data1> <data2/> <data3/> <dataN/> </Entry> <Entry> <Result> <id>XYZ</id> <amt>75.00</amt> </Result> <data1>KEY2</data1> <data2/> <data3/> <dataN/> </Entry> </Records>
期望输出XML
<?xml version="1.0" encoding="UTF-8"?> <Records> <Entry> <amt>200.25</amt> <relatedData> <data1>KEY</data1> <data2/> <data3/> <dataN/> </relatedData> </Entry> <Entry> <amt>80</amt> <relatedData> <data1>KEY1</data1> <data2/> <data3/> <dataN/> </relatedData> </Entry> <Entry> <amt>150.00</amt> <relatedData> <data1>KEY2</data1> <data2/> <data3/> <dataN/> </relatedData> </Entry> </Records>
当前错误的XSLT
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0"> <xsl:output indent="yes"/> <xsl:template match="Records"> <root> <xsl:for-each-group select="Entry" group-by="data1"> <Entry> <!-- Sum just amounts from unique entry IDs --> <!-- Doesn't account for unique entry IDs --> <amt> <xsl:value-of select="sum(distinct-values(current-group()/Result/amt))"/> </amt> <!-- output related data --> <relatedData> <data1> <xsl:value-of select="data1"/> </data1> <!-- Place holder code <data2> <xsl:value-of select='sum(current-group()/data2)'/> </data2> <data3> <xsl:value-of select='sum(current-group()/data3)'/> </data3> --> </relatedData> </Entry> </xsl:for-each-group> </root> </xsl:template> </xsl:stylesheet>
当前错误输出
<?xml version="1.0" encoding="UTF-8"?> <root> <Entry> <amt>200.25</amt> <relatedData> <data1>KEY</data1> </relatedData> </Entry> <Entry> <amt>80</amt> <relatedData> <data1>KEY1</data1> </relatedData> </Entry> <Entry> <!-- incorrect total, should be 150 --> <amt>75</amt> <relatedData> <data1>KEY2</data1> </relatedData> </Entry> </root>
解决方案
问题出在原XSLT仅对amt值去重求和,忽略了不同id可能对应相同amt的情况(比如KEY2分组里的AB90和XYZ,amt都是75.00,但属于不同id,需要各算一次)。
修改后的XSLT需要在每个data1分组内,先按Result/id做二次分组,然后取每个id分组对应的amt值(同一个id的amt值一致),再对这些值求和:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0"> <xsl:output indent="yes"/> <xsl:template match="Records"> <Records> <xsl:for-each-group select="Entry" group-by="data1"> <Entry> <!-- 先按id分组,取每个唯一id对应的amt,再求和 --> <amt> <xsl:value-of select="sum( for $group in current-group()/Result group by $group/id return xs:decimal($group/amt)[1] )"/> </amt> <!-- 输出相关数据,取当前分组第一个Entry的data2、data3等 --> <relatedData> <data1> <xsl:value-of select="data1"/> </data1> <data2> <xsl:value-of select="current-group()[1]/data2"/> </data2> <data3> <xsl:value-of select="current-group()[1]/data3"/> </data3> <dataN> <xsl:value-of select="current-group()[1]/dataN"/> </dataN> </relatedData> </Entry> </xsl:for-each-group> </Records> </xsl:template> </xsl:stylesheet>
说明
- 内层通过
for $group in current-group()/Result group by $group/id实现对每个data1分组内的id去重; - 每个唯一
id对应的amt取第一个值(因为输入里同一id的amt都是相同的),转换为xs:decimal避免字符串求和问题; - 对这些去重后的
amt值求和,得到正确结果; relatedData里的data2、data3等取当前data1分组第一个Entry的对应节点,符合期望输出格式。
内容的提问来源于stack exchange,提问作者J R
相关产品推荐
相关产品推荐

