I use a xsl to calculate the cumulative total per element "Basisproduct". The output has finally to be put in the same xml, after "Totals" in some new elements, like this:
<Totals>
<Totalproduct>
<Basisproduct>110</Basisproduct>
<Cumul_Amount>1,52</CustInvoice_LineAmount>
</Totalproduct>
<Totalproduct>
<Basisproduct>198</Basisproduct>
<Cumul_Amount>294,77</CustInvoice_LineAmount>
</Totalproduct>
<Totalproduct>
<Basisproduct>992</Basisproduct>
<Cumul_Amount>163,32</CustInvoice_LineAmount>
</Totalproduct>
<Totalproduct>
<Basisproduct>993</Basisproduct>
<Cumul_Amount>193,78</CustInvoice_LineAmount>
</Totalproduct>
<Totals>
<-----I have this xml as an input.------>
<?xml version="1.0" encoding="utf-8"?>
<Report Name="SalesInvoice">
<ReportName>SalesInvoice</ReportName>
<Invoice>
<InvoicingName>Test Company</InvoicingName>
</Invoice>
<ConditionalArea>
<BodyCustInvoice>
<Basisproduct>110</Basisproduct>
<CustInvoice_LineAmount>1,52</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>198</Basisproduct>
<CustInvoice_LineAmount>20,11</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>198</Basisproduct>
<CustInvoice_LineAmount>20,22</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>992</Basisproduct>
<CustInvoice_LineAmount>3033</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>993</Basisproduct>
<CustInvoice_LineAmount>30,34</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>992</Basisproduct>
<CustInvoice_LineAmount>30,35</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>992</Basisproduct>
<CustInvoice_LineAmount>30.45</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>993</Basisproduct>
<CustInvoice_LineAmount>30,46</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>198</Basisproduct>
<CustInvoice_LineAmount>100.99</CustInvoice_LineAmount>
</BodyCustInvoice>, </ConditionalArea>
<Totals>
</Totals>
</Report>
The xsl I use to calculate the cumlative sum of "Basisproduct" is:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output indent="yes"/> <xsl:strip-space elements="*"/>
<xsl:decimal-format name="EU" decimal-separator="," grouping-separator="."/>
<xsl:key name="KType" match="Basisproduct" use="."/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="TotalSBasis">
<TotalSBasis>
<xsl:for-each select="/*/*/*/Basisproduct [generate-id() = generate-id(key ('KType', .)[1]开发者_StackOverflow社区)]">
<xsl:variable name="currProd" select="."/>
<Totalproduct>
<xsl:copy-of select="."/>
<Cumul_Amount>
<xsl:value-of select="sum(/*/*/BodyCustInvoiceTrans [Basisproduct=$currProd]/CustInvoiceTrans_LineAmount)"/>
</Cumul_Amount>
</Totalproduct>
</xsl:for-each>
</TotalSBasis>
</xsl:template>
</xsl:stylesheet>
What you should do is use an identity transform and then just override the Totals
element.
EDIT: Based on a comment by the OP in @james.garriss answer, I modified the calculation to just sum everything.
Input XML
<Report Name="SalesInvoice">
<ReportName>SalesInvoice</ReportName>
<Invoice>
<InvoicingName>Test Company</InvoicingName>
</Invoice>
<ConditionalArea>
<BodyCustInvoice>
<Basisproduct>110</Basisproduct>
<CustInvoice_LineAmount>1.52</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>198</Basisproduct>
<CustInvoice_LineAmount>20.11</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>198</Basisproduct>
<CustInvoice_LineAmount>20.22</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>992</Basisproduct>
<CustInvoice_LineAmount>30.33</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>993</Basisproduct>
<CustInvoice_LineAmount>30.34</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>992</Basisproduct>
<CustInvoice_LineAmount>30.35</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>992</Basisproduct>
<CustInvoice_LineAmount>30.45</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>993</Basisproduct>
<CustInvoice_LineAmount>30.46</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>198</Basisproduct>
<CustInvoice_LineAmount>100.99</CustInvoice_LineAmount>
</BodyCustInvoice>
</ConditionalArea>
<Totals> </Totals>
</Report>
XSLT Stylesheet
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="KType" match="Basisproduct" use="."/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Totals">
<Totals>
<xsl:for-each select="/*/*/*/Basisproduct [generate-id() = generate-id(key ('KType', .)[1])]">
<xsl:variable name="currProd" select="."/>
<Totalproduct>
<xsl:copy-of select="."/>
<Cumul_Amount>
<!--<xsl:value-of select= "/*/*/*[Basisproduct = current()][last()]/CustInvoice_LineAmount + sum(/*/*/*[Basisproduct = current()][last()]/preceding-sibling::*/CustInvoice_LineAmount)"/>-->
<xsl:value-of select="sum(/*/*/BodyCustInvoice[Basisproduct=$currProd]/CustInvoice_LineAmount)"/>
</Cumul_Amount>
</Totalproduct>
</xsl:for-each>
</Totals>
</xsl:template>
</xsl:stylesheet>
Output XML (Using Xalan :-( )
<Report Name="SalesInvoice">
<ReportName>SalesInvoice</ReportName>
<Invoice>
<InvoicingName>Test Company</InvoicingName>
</Invoice>
<ConditionalArea>
<BodyCustInvoice>
<Basisproduct>110</Basisproduct>
<CustInvoice_LineAmount>1.52</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>198</Basisproduct>
<CustInvoice_LineAmount>20.11</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>198</Basisproduct>
<CustInvoice_LineAmount>20.22</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>992</Basisproduct>
<CustInvoice_LineAmount>30.33</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>993</Basisproduct>
<CustInvoice_LineAmount>30.34</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>992</Basisproduct>
<CustInvoice_LineAmount>30.35</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>992</Basisproduct>
<CustInvoice_LineAmount>30.45</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>993</Basisproduct>
<CustInvoice_LineAmount>30.46</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>198</Basisproduct>
<CustInvoice_LineAmount>100.99</CustInvoice_LineAmount>
</BodyCustInvoice>
</ConditionalArea>
<Totals>
<Totalproduct>
<Basisproduct>110</Basisproduct>
<Cumul_Amount>1.52</Cumul_Amount>
</Totalproduct>
<Totalproduct>
<Basisproduct>198</Basisproduct>
<Cumul_Amount>141.32</Cumul_Amount>
</Totalproduct>
<Totalproduct>
<Basisproduct>992</Basisproduct>
<Cumul_Amount>91.13</Cumul_Amount>
</Totalproduct>
<Totalproduct>
<Basisproduct>993</Basisproduct>
<Cumul_Amount>60.8</Cumul_Amount>
</Totalproduct>
</Totals>
</Report>
<Totals>
<xsl:for-each select="*/*/*/Basisproduct [generate-id() = generate-id(key ('KType', .)[1])]">
<Totalproduct>
<Basisproduct><xsl:value-of select= "."/></Basisproduct>
<Cumul_Amount>
<xsl:value-of select= "/*/*/*[Basisproduct = current()][last()]/CustInvoice_LineAmount + sum(/*/*/*[Basisproduct = current()][last()]/preceding-sibling::*/CustInvoice_LineAmount)"/>
</Cumul_Amount>
</Totalproduct>
</xsl:for-each>
</Totals>
This would output xml in the form mentioned, with the results you showed.
Edit: Updated my XSLT to accommodate OP's request to insert totals into the original XML. The trick to solving the problem is to use the identity template and a global variable.
If you use this XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="KType" match="Basisproduct" use="."/>
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- create a variable w/ the calculated totals -->
<xsl:variable name="CalculatedTotals">
<xsl:for-each select="*/*/*/Basisproduct [generate-id() = generate-id(key ('KType', .)[1])]">
<xsl:element name="TotalProduct">
<xsl:element name="Basisproduct">
<xsl:value-of select= "."/>
</xsl:element>
<xsl:element name="Cumul_Amount">
<xsl:value-of select= "/*/*/*[Basisproduct = current()][last()]/CustInvoice_LineAmount + sum(/*/*/*[Basisproduct = current()][last()]/preceding-sibling::*/CustInvoice_LineAmount)"/>
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:variable>
<!-- identity -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<!-- root -->
<xsl:template match="/">
<xsl:apply-templates select="node()|@*"/>
</xsl:template>
<xsl:template match="Totals">
<xsl:copy>
<!-- insert the calculated totals -->
<xsl:copy-of select="$CalculatedTotals"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
You will get this XML output:
<?xml version="1.0" encoding="utf-8"?>
<Report Name="SalesInvoice">
<ReportName>SalesInvoice</ReportName>
<Invoice>
<InvoicingName>Test Company</InvoicingName>
</Invoice>
<ConditionalArea>
<BodyCustInvoice>
<Basisproduct>110</Basisproduct>
<CustInvoice_LineAmount>1.52</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>198</Basisproduct>
<CustInvoice_LineAmount>20.11</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>198</Basisproduct>
<CustInvoice_LineAmount>20.22</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>992</Basisproduct>
<CustInvoice_LineAmount>30.33</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>993</Basisproduct>
<CustInvoice_LineAmount>30.34</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>992</Basisproduct>
<CustInvoice_LineAmount>30.35</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>992</Basisproduct>
<CustInvoice_LineAmount>30.45</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>993</Basisproduct>
<CustInvoice_LineAmount>30.46</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>198</Basisproduct>
<CustInvoice_LineAmount>100.99</CustInvoice_LineAmount>
</BodyCustInvoice>
</ConditionalArea>
<Totals>
<TotalProduct>
<Basisproduct>110</Basisproduct>
<Cumul_Amount>1.52</Cumul_Amount>
</TotalProduct>
<TotalProduct>
<Basisproduct>198</Basisproduct>
<Cumul_Amount>294.77</Cumul_Amount>
</TotalProduct>
<TotalProduct>
<Basisproduct>992</Basisproduct>
<Cumul_Amount>163.32</Cumul_Amount>
</TotalProduct>
<TotalProduct>
<Basisproduct>993</Basisproduct>
<Cumul_Amount>193.78000000000003</Cumul_Amount>
</TotalProduct>
</Totals>
</Report>
Tested with Oxygen 12 on Win 7.
This transform groups elements by Basisproduct
and calculates the total sum of each group. Note that it includes by identity.xsl
the well known Identity Transformation.
[XSLT 1.0]
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:include href="identity.xsl"/>
<xsl:key name="KType" match="BodyCustInvoice" use="Basisproduct"/>
<xsl:template match="Totals">
<Totals>
<xsl:apply-templates select="
preceding-sibling::ConditionalArea[1]/BodyCustInvoice
[generate-id()
= generate-id(key ('KType', Basisproduct)[1])]" mode="totals"/>
</Totals>
</xsl:template>
<xsl:template match="BodyCustInvoice" mode="totals">
<Totalproduct>
<Basisproduct><xsl:value-of select="Basisproduct"/></Basisproduct>
<Cumul_Amount>
<xsl:value-of select="
sum(key('KType',Basisproduct)/CustInvoice_LineAmount)"/>
</Cumul_Amount>
</Totalproduct>
</xsl:template>
</xsl:stylesheet>
output:
<Report Name="SalesInvoice">
<ReportName>SalesInvoice</ReportName>
<Invoice>
<InvoicingName>Test Company</InvoicingName>
</Invoice>
<ConditionalArea>
<BodyCustInvoice>
<Basisproduct>110</Basisproduct>
<CustInvoice_LineAmount>1.52</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>198</Basisproduct>
<CustInvoice_LineAmount>20.11</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>198</Basisproduct>
<CustInvoice_LineAmount>20.22</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>992</Basisproduct>
<CustInvoice_LineAmount>30.33</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>993</Basisproduct>
<CustInvoice_LineAmount>30.34</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>992</Basisproduct>
<CustInvoice_LineAmount>30.35</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>992</Basisproduct>
<CustInvoice_LineAmount>30.45</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>993</Basisproduct>
<CustInvoice_LineAmount>30.46</CustInvoice_LineAmount>
</BodyCustInvoice>
<BodyCustInvoice>
<Basisproduct>198</Basisproduct>
<CustInvoice_LineAmount>100.99</CustInvoice_LineAmount>
</BodyCustInvoice>
</ConditionalArea>
<Totals>
<Totalproduct>
<Basisproduct>110</Basisproduct>
<Cumul_Amount>1.52</Cumul_Amount>
</Totalproduct>
<Totalproduct>
<Basisproduct>198</Basisproduct>
<Cumul_Amount>141.32</Cumul_Amount>
</Totalproduct>
<Totalproduct>
<Basisproduct>992</Basisproduct>
<Cumul_Amount>91.13</Cumul_Amount>
</Totalproduct>
<Totalproduct>
<Basisproduct>993</Basisproduct>
<Cumul_Amount>60.8</Cumul_Amount>
</Totalproduct>
</Totals>
</Report>
精彩评论