Grouping with <xsl:variable>

We mentioned earlier that sometimes <xsl:variable> is useful for grouping, so let’s try that approach. We’ll save the value of the <zip> element each time through the <xsl:for-each> element and use preceding-sibling in a slightly different way. Here’s how attempt number three looks:

<?xml version="1.0"?>
<!-- namegrouper3.xsl -->
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="text" indent="no"/>

  <xsl:template match="/">
    <xsl:text>Addresses sorted by zip code&#xA;</xsl:text>
    <xsl:for-each select="addressbook/address">
      <xsl:sort select="zip"/>
      <xsl:variable name="lastZip" select="zip"/>
      <xsl:if test="not(preceding-sibling::address[zip=$lastZip])">
        <xsl:text>Zip code </xsl:text>
        <xsl:value-of select="zip"/>
        <xsl:text>: &#xA;</xsl:text>
        <xsl:for-each select="/addressbook/address[zip=$lastZip]">
          <xsl:sort select="name/last-name"/>
          <xsl:sort select="name/first-name"/>
          <xsl:if test="name/title">
            <xsl:value-of select="name/title"/>
            <xsl:text> </xsl:text>
          </xsl:if>
          <xsl:value-of select="name/first-name"/>
          <xsl:text> </xsl:text>
          <xsl:value-of select="name/last-name"/>
          <xsl:text>&#xA;</xsl:text>
          <xsl:value-of select="street"/>
          <xsl:text>&#xA;&#xA;</xsl:text>
        </xsl:for-each>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

This stylesheet generates what we want:

Addresses sorted by Zip Code Zip code 00218: Ms. Natalie Attired 707 Breitling Way Zip code 02718: Harry Backstayge 283 First Avenue Mary Backstayge ...

Get XSLT, 2nd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.