通过在XSLT中分组来节点的总和

时间:2014-05-07 19:07:38

标签: xml xslt

我需要将少数具有公共ID的节点的值相加。

我的输入XML如下:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Rowsets CachedTime="" DateCreated="2014-05-01T13:11:42" EndDate="2014-05-01T13:11:42" StartDate="2014-05-01T12:11:42" Version="14.0 SP4 Patch 0 (Nov 22, 2013)">
    <Rowset>
        <Columns>
            <Column Description="ID" MaxRange="1" MinRange="0" Name="ID" SQLDataType="12" SourceColumn="ID"/>
            <Column Description="Name" MaxRange="1" MinRange="0" Name="Name" SQLDataType="12" SourceColumn="Name"/>
            <Column Description="ProductCode" MaxRange="1" MinRange="0" Name="ProductCode" SQLDataType="1" SourceColumn="ProductCode"/>
            <Column Description="NoOfMachine" MaxRange="1" MinRange="0" Name="NoOfMachine" SQLDataType="1" SourceColumn="NoOfMachine"/>
            <Column Description="MPerHour" MaxRange="1" MinRange="0" Name="MPerHour" SQLDataType="3" SourceColumn="MPerHour"/>
            <Column Description="TargetProduction" MaxRange="1" MinRange="0" Name="TargetProduction" SQLDataType="3" SourceColumn="TargetProduction"/>
            <Column Description="ActualProduction" MaxRange="1" MinRange="0" Name="ActualProduction" SQLDataType="3" SourceColumn="ActualProduction"/>
        </Columns>
        <Row>
            <ID>S111</ID>
            <Name/>
            <ActualHours>25</ActualHours>
            <ProductCode>16J16</ProductCode>
            <NoOfMachine>5</NoOfMachine>
            <MPerHour>10</MPerHour>
            <TargetProduction>225.50</TargetProduction>
            <ActualProduction>300.75</ActualProduction>
        </Row>
        <Row>
            <ID>S111</ID>
            <Name/>
            <ActualHours>20</ActualHours>
            <ProductCode>16J16</ProductCode>
            <NoOfMachine>2</NoOfMachine>
            <MPerHour>10</MPerHour>
            <TargetProduction>24.50</TargetProduction>
            <ActualProduction>1.25</ActualProduction>
        </Row>
        <Row>
            <ID>S112</ID>
            <Name/>
            <ActualHours>25</ActualHours>
            <ProductCode>16J26</ProductCode>
            <NoOfMachine>5</NoOfMachine>
            <MPerHour>10</MPerHour>
            <TargetProduction>225.50</TargetProduction>
            <ActualProduction>300.75</ActualProduction>
        </Row>
        <Row>
            <ID>S111</ID>
            <Name/>
            <ActualHours>5</ActualHours>
            <ProductCode>16J16</ProductCode>
            <NoOfMachine>1</NoOfMachine>
            <MPerHour>10</MPerHour>
            <TargetProduction>5</TargetProduction>
            <ActualProduction>300</ActualProduction>
        </Row>
    </Rowset>
</Rowsets>

我想总结<ActualHours><NoOfMachines><MPerHour><TargetProduction><ActualProduction>的公共ID值。

因此输出XML将如下所示:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Rowsets CachedTime="" DateCreated="2014-05-01T13:11:42" EndDate="2014-05-01T13:11:42" StartDate="2014-05-01T12:11:42" Version="14.0 SP4 Patch 0 (Nov 22, 2013)">
    <Rowset>
        <Columns>
            <Column Description="ID" MaxRange="1" MinRange="0" Name="ID" SQLDataType="12" SourceColumn="ID"/>
            <Column Description="Name" MaxRange="1" MinRange="0" Name="Name" SQLDataType="12" SourceColumn="Name"/>
            <Column Description="ProductCode" MaxRange="1" MinRange="0" Name="ProductCode" SQLDataType="1" SourceColumn="ProductCode"/>
            <Column Description="NoOfMachine" MaxRange="1" MinRange="0" Name="NoOfMachine" SQLDataType="1" SourceColumn="NoOfMachine"/>
            <Column Description="MPerHour" MaxRange="1" MinRange="0" Name="MPerHour" SQLDataType="3" SourceColumn="MPerHour"/>
            <Column Description="TargetProduction" MaxRange="1" MinRange="0" Name="TargetProduction" SQLDataType="3" SourceColumn="TargetProduction"/>
            <Column Description="ActualProduction" MaxRange="1" MinRange="0" Name="ActualProduction" SQLDataType="3" SourceColumn="ActualProduction"/>
        </Columns>
        <Row>
            <ID>S111</ID>
            <Name/>
            <ActualHours>50</ActualHours>
            <ProductCode>16J16</ProductCode>
            <NoOfMachine>8</NoOfMachine>
            <MPerHour>30</MPerHour>
            <TargetProduction>255</TargetProduction>
            <ActualProduction>602</ActualProduction>
        </Row>
        <Row>
            <ID>S112</ID>
            <Name/>
            <ActualHours>25</ActualHours>
            <ProductCode>16J26</ProductCode>
            <NoOfMachine>5</NoOfMachine>
            <MPerHour>10</MPerHour>
            <TargetProduction>225.50</TargetProduction>
            <ActualProduction>300.75</ActualProduction>
        </Row>
    </Rowset>
</Rowsets>

任何人都可以帮助我如何通过xslt实现这一目标。

1 个答案:

答案 0 :(得分:2)

您可以使用选择节点并按ID分组:

 <xsl:key name="rows" match="Row" use="ID"/>

然后选择每个相似节点一次,与键相比:

<xsl:template match="Rowset">
    <xsl:copy>
        <xsl:apply-templates select="Row[generate-id(.) = generate-id(key('rows', ID))]"/>
    </xsl:copy>
</xsl:template>

要对所有值求和,可以为要求求和的每个节点使用XPath表达式:

sum(//Row[ID='S112']/ActualHours)

并在模板中为每个不同的ID使用它。

编辑:更好的解决方案(由@IanRoberts建议)使用我们生成的密钥,并根据正在处理的当前节点的ID选择每个密钥:

sum(key('rows', ID)/ActualHours)

(以上示例适用于Row上下文。)

这是一个完整的样式表,它使用这些转换,您可以将其作为起点:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:key name="rows" match="Row" use="ID"/>

    <xsl:template match="Rowset">
        <xsl:copy>
            <xsl:apply-templates select="Row[generate-id(.) = generate-id(key('rows', ID))]"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Row">
        <xsl:copy>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="ActualHours | NoOfMachine | MPerHour | TargetProduction | ActualProduction">
        <xsl:variable name="tag-name" select="name()"/>
        <xsl:copy>
            <xsl:value-of select="sum(key('rows', ../ID)/*[$tag-name=name()])"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Name | ID | ProductCode">
        <xsl:copy>
            <xsl:value-of select="."/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>