I ran across a post over at the MSDN SharePoint – Design and Customization forum which intrigued me enough to want to figure it out. The question was about showing subtotals for a given column’s values, with the results sorted by the subtotal, descending.
In other words, for a list with these items:
| Title | Amount |
| Bob | 20 |
| Chrissy | 10 |
| Bob | 5 |
| Mabel | 50 |
Return this:
| Title | Amount |
| Mabel | 50 |
| Bob | 25 |
| Chrissy | 10 |
Here’s the code to do it. The tricky parts were to get the xsl:sort value right and then to display the items with duplicates removed using ddwrt:NameChanged. I’m sure that there are more efficient ways to do this, but this one works!
<xsl:template name="dvt_1.body"> <xsl:param name="Rows"/> <xsl:for-each select="$Rows"> <xsl:sort select="sum($Rows[current()/@Title=@Title]/@Amount)" data-type="number" order="descending" /> <xsl:call-template name="dvt_1.rowview"> <xsl:with-param name="Rows" select="$Rows"/> </xsl:call-template> </xsl:for-each> </xsl:template> <xsl:template name="dvt_1.rowview"> <xsl:param name="Rows"/> <xsl:variable name="NewTitle" select="ddwrt:NameChanged(string(@Title), 0)"/> <xsl:if test="string-length($NewTitle) > 0"> <tr> <td class="ms-vb"> <xsl:value-of select="@Title"/> </td> <td class="ms-vb"> <xsl:value-of select="sum($Rows[current()/@Title=@Title]/@Amount)"/> </td> </tr> </xsl:if> </xsl:template>
UPDATE 2009-05-21: I just found another approach over at Christian’s Pampigt blog. By changing the xsl:for-each to test for unique Titles, we don’t need to do the work in the dvt_1.rowview template below. I don’t know that this would be any more efficient (I’m sure the XSL gurus out there would know), but it’s a nice alternate approach.
<xsl:template name="dvt_1.body"> <xsl:param name="Rows"/> <xsl:for-each select="$Rows[not(@Title = preceding-sibling::*/@Title)]"> <xsl:sort select="sum($Rows[current()/@Title=@Title]/@Amount)" data-type="number" order="descending" /> <xsl:call-template name="dvt_1.rowview"> <xsl:with-param name="Rows" select="$Rows"/> </xsl:call-template> </xsl:for-each> </xsl:template> <xsl:template name="dvt_1.rowview"> <xsl:param name="Rows"/> <tr> <td class="ms-vb"> <xsl:value-of select="@Title"/> </td> <td class="ms-vb"> <xsl:value-of select="sum($Rows[current()/@Title=@Title]/@Amount)"/> </td> </tr> </xsl:template>