使用具有相同项目的XML行中的XSLT计算总和

时间:2016-05-10 09:22:27

标签: xml xslt

我很抱歉我的英语,这不是母语,所以有些词和术语可能是错误的。

我有XML,其中有很多项目。有些物品可能很多次。我希望它是hatml表,但是相同的项目只是一次监听,总计已经总结。

正常for-each很简单,但它只列出了一切。我怎样才能为我的XSLT添加一些条件等?

以下是我的示例XML:

<Amounts>
    <item>
        <id>02</id>
        <name>Item2</name>
        <amount>20</amount>
    </item>
    <item>
        <id>01</id>
        <name>Item1</name>
        <amount>80</amount>
    </item>
    <item>
        <id>06</id>
        <name>Item6</name>
        <amount>50</amount>
    </item>
    <item>
        <id>02</id>
        <name>Item2</name>
        <amount>150</amount>
    </item>
</Amounts>

现在这是我的XSLT:

<table>
<tr>
    <td>id</td>
    <td>name</td>
    <td>total</td>
</tr>
<xsl:for-each select="/Amounts/item">
<tr>
    <td><xsl:value-of select="id"/></td>
    <td><xsl:value-of select="name"/></td>
    <td><xsl:value-of select="amount"/></td>
</tr>
</table>

但这就是我不想做的事情:

<table>
<tr>
    <td>id</td>
    <td>name</td>
    <td>total</td>
</tr>
<tr>
    <td>01</td>
    <td>Item1</td>
    <td>80</td>
</tr>
<tr>
    <td>02</td>
    <td>Item2</td>
    <td>170</td>
</tr>
<tr>
    <td>06</td>
    <td>Item6</td>
    <td>50</td>
</tr>   
</table>

2 个答案:

答案 0 :(得分:1)

使用Muenchian grouping,您可以使用

在XSLT 1.0中解决这个问题
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:output method="html"/>

    <xsl:key name="group" match="item" use="id"/>

    <xsl:template match="Amounts">
        <table>
            <thead>
                <tr>
                    <th>Id</th>
                    <th>Name</th>
                    <th>Amount</th>
                </tr>
            </thead>
            <tbody>
                <xsl:apply-templates select="item[generate-id() = generate-id(key('group', id)[1])]">
                    <xsl:sort select="id" data-type="number"/>
                </xsl:apply-templates>
            </tbody>
        </table>
    </xsl:template>

    <xsl:template match="item">
        <tr>
            <td>
                <xsl:value-of select="id"/>
            </td>
            <td>
                <xsl:value-of select="name"/>
            </td>
            <td>
                <xsl:value-of select="sum(key('group', id)/amount)"/>
            </td>
        </tr>
    </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:0)

XSLT 1.0 :解决方案的主要思想是在id属性值上使用一个键, 如https://stackoverflow.com/a/2293626/2156349中所述。

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"
    >
    <xsl:output method="html" indent="yes" />       
    <xsl:strip-space elements="*"/>

    <xsl:key name="itemsKey" match="item/id/text()" use="." />

    <xsl:template match="/">
        <html>
        <head>  <title>Solution</title> </head>
        <body>  <xsl:apply-templates /> </body>
        </html>
    </xsl:template>

    <xsl:template match="Amounts">
        <table>
            <tr>
                <td>id</td>
                <td>name</td>
                <td>total</td>
            </tr>
            <xsl:for-each select="item">
                <xsl:variable name="idText" select="id/text()" />
                <xsl:variable name="myId"   select="generate-id($idText)" />
                <xsl:variable name="firstId" select="generate-id(key('itemsKey',$idText)[1])" />

                <xsl:if test="$myId = $firstId">
                    <xsl:apply-templates select="." />
                </xsl:if>
            </xsl:for-each>
        </table>
    </xsl:template>

    <xsl:template match="item">
        <xsl:variable name="idValue" select="id" />
        <tr>
            <td><xsl:value-of select="id"/></td>
            <td><xsl:value-of select="name"/></td>
            <td><xsl:value-of select="sum(//item[id=$idValue]/amount)"/></td>
        </tr>
    </xsl:template>

</xsl:stylesheet>

XSLT 2.0 :使用上面的Martin Honnen的提示,使用XSLT 2.0可以大大简化整个转换:

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0"
    >
    <xsl:output method="html" indent="yes" />
    <xsl:strip-space elements="*"/>

    <xsl:template match="/">
        <html>
        <head> <title>Solution</title> </head>
        <body> <xsl:apply-templates /> </body>
        </html>
    </xsl:template>

    <xsl:template match="Amounts">
        <table>
            <tr>
                <td>id</td>
                <td>name</td>
                <td>total</td>
            </tr>
            <xsl:for-each-group select="item" group-by="id">
                <tr>
                    <td><xsl:value-of select="id"/></td>
                    <td><xsl:value-of select="name"/></td>
                    <td><xsl:value-of select="sum(current-group()/amount)"/></td>
                </tr>
            </xsl:for-each-group>
        </table>
    </xsl:template>

</xsl:stylesheet>