Grouping in XSLT 2.0

I have been helping one of my colleagues on an engagement that has a complex project Gantt chart as part of a custom Project Lifecycle Management application.  The chart involves multi-level grouping of the data from a number of SharePoint Lists so it was an excellent opportunity to take advantage of the ability to utilize XSLT 2.0 as supported by the CorasWorks Application Service (available for both SharePoint 2010 & 2013).

XSLT 2.0 has some significant advantages over XSLT 1.0, including improved support for data types, custom functions and data parsing.  One of the other major improvements – and the reason I was excited about working on the Gantt chart solution – is the ease with which data can be grouped.  Grouping and especially multi-level grouping with XSLT 1.0 can be quite laborious and prone to errors.  A popular and efficient method of grouping in XSLT 1.0 is Meunchian grouping, wherein keys are defined that will be used in the select attribute of the <xsl:for-each> instruction so the processor knows which data values to group on.  Each additional level requires that a new key be defined and that the grouping value used be a concatenation of the preceding key’s value with the current grouping value.

Various examples of grouping with XSLT 1.0 are located at Jeni Tennison’s site, and here’s the basic form for multi-level grouping:

<xsl:key name="service_row" match="SetDailySetRpt:SettleItem" use="SetDailySetRpt:ServiceCode" />

<xsl:key name="exchange" match="SetDailySetRpt:SettleItem" use="concat(SetDailySetRpt:ServiceCode, ' ', SetDailySetRpt:ExchangeName, ' ', SetDailySetRpt:ExchangeCode)" />

<xsl:variable name="service_items" select="key('service_rows', SetDailySetRpt:ServiceCode)" />

<xsl:for-each select="$service_items[generate-id() = generate-id( key('exchange', concat(SetDailySetRpt:ServiceCode, ' ', SetDailySetRpt:ExchangeName, ' ', SetDailySetRpt:ExchangeCode))[1])]">
  <xsl:value-of select="SetDailySetRpt:ExchangeName" />
  <xsl:text> - </xsl:text>
  <xsl:value-of select="SetDailySetRpt:ExchangeCode" />

I have used this grouping method with great success on a variety of reports and displays, but it can be frustrating to make sure you have all the keys, variables and select attributes within the <xsl:for-each> instruction properly written.

With XSLT 2.0, life is much simpler when it comes to grouping.  No longer do you need to define keys and declare variables.  Here’s an example of multi-level grouping with XSLT 2.0:

<xsl:for-each-group select="NewDataSet/Data" group-by="LEVEL_1_DATA">
  <xsl:value-of select="current-grouping-key()"/>
  <xsl:for-each-group select="current-group()" group-by=" LEVEL_2_DATA ">
    <xsl:value-of select="current-grouping-key()"/>
    <xsl:for-each-group select="current-group()" group-by="LEVEL_2_DATA ">
      <xsl:value-of select="current-grouping-key()"/>
      <xsl:for-each select="current-group()">
        <xsl:value-of select="ITEMS"/>

The first thing you’ll notice is that we are using XSLT 2.0’s <xsl:for-each-group> instruction at each grouping level and that there is a group-by attribute that lets us quickly define what we want to group the populate of data on at that level.  As we traverse down the hierarchy, we can simply reference the current group we are in by setting the select attribute to use the current-group() XPATH expression. For more information, check out this great discussion about XSLT 2.0’s <xsl:for-each-group> instruction and its various attributes can be found here.

Comments are closed.