Our First Attempt

For our first example, we’ll take our list of addresses and group them. We’ll look for all unique values of the <zip> element and list the addresses that match each one. We’ll sort the list by zip code, then go through the list. If a given item doesn’t match the previous zip code, we’ll print out a heading; if it does match, we’ll just print out the address. Here’s our first attempt:

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

  <xsl:output method="text"/>

  <xsl:template match="/">
    <xsl:text>Addresses grouped by zip code &#xA;</xsl:text>
    <xsl:for-each select="addressbook/address">
      <xsl:sort select="zip"/>
      <xsl:if test="zip!=preceding-sibling::address[1]/zip">
        <xsl:text>&#xA;Zip code </xsl:text>
        <xsl:value-of select="zip"/>
        <xsl:text> (</xsl:text>
        <xsl:value-of select="city"/>
        <xsl:text>, </xsl:text>
        <xsl:value-of select="state"/>
        <xsl:text>): &#xA;</xsl:text>
      </xsl:if>
      <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:template>
</xsl:stylesheet>

Our approach in this stylesheet consists of two steps:

  1. Sort the addresses by zip code:

    <xsl:sort select="zip"/>
  2. For each address, if its zip code doesn’t match the previous one, print out ...

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.