Question
I am new to working with XSLT and am trying to create a pivot table using the Muenchian Method (since it appear that IE still doesn't support XSLT 2.0 I think I'm stuck with this). I am able to get the desired grouping however I am trying to get the sum of an attribute for each group. To do the sum of the attribute can I use the aggregate sum function or do I have to loop through the keys and store the values into a variable? This is what I have so far:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" encoding="UTF-8"/>
<xsl:key name="Person" match="Record" use="@PersonID" />
<xsl:template match="/">
<html>
<body>
<h2>Costs Per Person</h2>
<table border = "1">
<thead>
<tr>
<th>ID</th>
<th>Cost</th>
</tr>
</thead>
<tbody>
<xsl:for-each select="Records/Record[generate-id() =
generate-id(key('Person', @PersonID)[1])]">
<tr>
<td>
<xsl:value-of select="@PersonID" />
</td>
<td>
<!-- Sum Of Cost -->
</td>
</tr>
</xsl:for-each>
</tbody>
</table>
</body>
</html>
</xsl:template>
Solution
Easy - you where already there. See full solution below.
On a different note, I advise against the use of <xsl:for-each>
in favor of <xsl:apply-templates>
. The code gets a bit longer, but readability and code structure improves, IMHO.
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="html" indent="yes" encoding="UTF-8"/>
<xsl:key name="Person" match="Record" use="@PersonID" />
<xsl:template match="/">
<html>
<body>
<h2>Costs Per Person</h2>
<table border = "1">
<thead>
<tr>
<th>ID</th>
<th>Cost</th>
</tr>
</thead>
<tbody>
<xsl:apply-templates select="Records/Record" />
</tbody>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="Records/Record">
<xsl:variable name="thisGroup" select"key('Person', @PersonID)" />
<xsl:if test="generate-id() = generate-id($thisGroup[1])">
<tr>
<td>
<xsl:value-of select="@PersonID" />
</td>
<td>
<!-- Sum Of Cost -->
<xsl:value-of select="sum($thisGroup/@Cost)" />
</td>
</tr>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
OTHER TIPS
Because your current context node inside the loop is a Record element, you will need to ensure your 'sum' includes all Records with a matching PersonID attribute. Something like this should do:
<xsl:value-of select="sum(../Record[@PersonID=current()/@PersonID]/@Cost)" />
Or, because you know the current Record element is the first with a particular PersonID attribute, you could also do this in this case
<xsl:value-of select="number(@Cost) + sum(following-sibling::Record[@PersonID=current()/@PersonID]/@Cost)" />
You should be able to use sum if you can use an xpath to select the attribute for the desired record(s).
Without knowing the structure of your input xml i don't know what this would be but I guess in your case something like <xsl:value-of select="sum(@cost)"/>