Search code examples
xmlxsltxslt-grouping

XSLT: wanting to group similar output values and give them relevant headers


I'm brand new to XML and XSLT, so any guidance is deeply appreciated. I am unable to resolve my issue through researching on my own.

The Tools I'm using: I am using the Enhanced Query Export extension for VSTS. This allows you to write an XML document to export your work items in a format of your desire.

The Goal: I'd like my output to group work items by their work item type, and give these grouped work types specific headers. For example:

FIXES:
Bugs we've fixed

TITLE   TYPE   DESCRIPTION
B1      Bug    B1info
B2      Bug    B2info
B3      Bug    B3info

...

IMPROVEMENTS:
Improvements we've made to the current features.

TITLE   TYPE     DESCRIPTION
I1      Backlog  I1info
I2      Backlog  I2info
I3      Backlog  I3info

...

Current HTML Output Example:
Here's an image of what my output looks like with my current code.

Here's what my output looks like with my current code.

Current Code:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" indent="yes"/>

<xsl:key name="workitem" match="//workitem" use="System.WorkItemType" />

  <xsl:template match="//workitem">
  <html>
<body>
    <table border="1">
      <tr bgcolor="#9acd32">
      <th>Title</th>
      <th>Type</th>
      <th>Description</th>      
    </tr>
    <xsl:for-each select="key('workitem',System.WorkItemType)">

     <xsl:choose>

      <xsl:when test="System.WorkItemType = 'Bug' ">
              <h1>Fixes</h1>
              <h2>Bugs we've fixed.</h2>
                <tr>
                  <td><xsl:value-of select="System.Title"/></td>
                 <td><xsl:value-of select="System.WorkItemType"/></td>
                 <td><xsl:value-of select="System.Description"/></td>
               </tr>
      </xsl:when>
      <xsl:when test="System.WorkItemType = 'Product Backlog Item' ">
              <h1>Improvements</h1>
              <h2>Improvements we've made to existing functionality.</h2>
                <tr>
                  <td><xsl:value-of select="System.Title"/></td>
                 <td><xsl:value-of select="System.WorkItemType"/></td>
                 <td><xsl:value-of select="System.Description"/></td>
               </tr>
      </xsl:when>
     </xsl:choose>
    </xsl:for-each>
    </table>
  </body>
  </html>
  <xsl:apply-templates select="workitem" />
  </xsl:template>

</xsl:stylesheet>

Solution

  • Thanks, folks, for your comments and suggestions. I looked up Muenchian grouping as suggested by /u/tim-c and this was the solution I was looking for. I am grateful for everyone's hints to help this newbie! The code now works when formatted as follows (I've since added some additional formatting):

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="html" indent="yes"/>
    
      <xsl:key name="wit" match="//workitem" use="System.WorkItemType" />
    
      <xsl:template match="/*">
        <html>
          <div style="width:600px; margin: 0 auto; margin-top:40px">
    
            <span class="title">What's New in</span>
            <img class="logo" src="images/app_name.svg" width="252" height="40" alt="" />
    
            <div class="body_copy">Unlike traditional dashboards or IT tools, Leading Wisely is a self-service, flexible tool that is not IT dependent, enabling users to set and monitor their choice of measure and alerts themselves.</div>
    
            <xsl:for-each select="//workitem
                  [generate-id() = generate-id(key('wit', System.WorkItemType)[1])]">
              <xsl:sort select="System.WorkItemType" />
              <h1>
                <xsl:value-of select="System.WorkItemType" />
              </h1>
              <xsl:for-each select="key('wit', System.WorkItemType)">
                <xsl:sort select="System.Title" />
                <h3>
                  <xsl:value-of select="System.Title" />
                </h3>
                <xsl:value-of select="System.Description" />
              </xsl:for-each>
            </xsl:for-each>
          </div>
          </html>
      </xsl:template>
    </xsl:stylesheet>