Creating a Comma-Separated List of Items

MSXML 5.0 SDK

Microsoft XML Core Services (MSXML) 5.0 for Microsoft Office - XPath Developer's Guide

Creating a Comma-Separated List of Items

The last() function can be used to determine if the element is the last one in the query.

<DIV>
  <xsl:for-each select="products/product">
    <xsl:value-of select="."/> <xsl:if test="position()!=last()">, </xsl:if> 
    </xsl:for-each>
</DIV>

Because the comma is being inserted based on the position in the query and not the source document, the list can be sorted without creating errors in the results. The following template shows how to add commas to a sorted product list.

<DIV>
  <xsl:for-each select="products/product">
    <xsl:sort select="product" order="descending"/>
      <xsl:value-of select="."/><xsl:if test="position()!=last()">, </xsl:if> 
  </xsl:for-each>
</DIV>

The <xsl:sort> order attribute is given the value "descending" to indicate a descending sort by product name. The preceding two code snippets are shown in the following example.

You can separate the comma logic from outputting the element value. In the following template rule, the names in a group of names are formatted as a comma-separated list.

<xsl:template match="namelist/name">
  <xsl:apply-templates/>
  <xsl:if test="position()!=last()">, </xsl:if>
</xsl:template>

Another way to separate the comma and node printing is by reversing the logic to verify whether this name is the first. In some cases, this performs better than the preceding example because last() requires that the entire set of names be found and counted, while this one does not.

<xsl:template match="namelist/name">
  <xsl:if test="position()!=1">, </xsl:if>
  <xsl:apply-templates/>
</xsl:template>

The preceding two snippets are used with another template rule to display the name value itself:

<xsl:template match="name">
   <xsl:value-of select=".">
</xsl:template>

Example

XML File (product-list2.xml)

<?xml version='1.0'?>
<?xml-stylesheet type="text/xsl" href="product-list2.xsl"?>
<products>
   <product>ActiMates Arthur</product>
   <product>ActiMates Barney</product>
   <product>ActiMates DW</product>
   <product>ActiMates PC Pack</product>
   <product>ActiMates TV Pack</product>
   <product>Arthur's Brainteasers</product>
   <product>Arthur's Math Carnival</product>
   <product>Arthur's Reading Roundup</product>
   <product>Barney fun on the Farm</product>
   <product>Barney goes to the Circus</product>
   <product>Barney under the Sea</product>
</products>

XSLT File (product-list2.xsl)

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

<xsl:template match="/">
  <HTML>
    <BODY STYLE="font:10pt Arial">
      <DIV><B>Comma separated list:</B></DIV>
      <DIV>
        <xsl:for-each select="products/product">
          <xsl:value-of select="."/> <xsl:if test="position()!=last()">, </xsl:if> 
          </xsl:for-each>
      </DIV>
      <BR/>
      
      <DIV><B>Comma separated and reverse-sorted list:</B></DIV>
      <DIV>
        <xsl:for-each select="products/product">
          <xsl:sort select="product" order="descending"/>
            <xsl:value-of select="."/><xsl:if test="position()!=last()">, </xsl:if> 
        </xsl:for-each>
      </DIV>
    </BODY>
  </HTML>
</xsl:template>

</xsl:stylesheet>

Formatted Output

Comma separated list:
ActiMates Arthur, ActiMates Barney, ActiMates DW, ActiMates PC Pack, ActiMates TV Pack, Arthur's Brainteasers, Arthur's Math Carnival, Arthur's Reading Roundup, Barney fun on the Farm, Barney goes to the Circus, Barney under the Sea
Comma separated and reverse-sorted list:
Barney under the Sea, Barney goes to the Circus, Barney fun on the Farm, Arthur's Reading Roundup, Arthur's Math Carnival, Arthur's Brainteasers, ActiMates TV Pack, ActiMates PC Pack, ActiMates DW, ActiMates Barney, ActiMates Arthur

Processor Output

<HTML>
<BODY STYLE="font:10pt Arial">
<DIV><B>Comma separated list:</B></DIV>
<DIV>ActiMates Arthur, ActiMates Barney, ..., Barney under the Sea</DIV><BR><DIV><B>Comma separated and reverse-sorted list:</B></DIV>
<DIV>Barney under the Sea, Barney goes to the Circus, ..., ActiMates Arthur</DIV>
</BODY>
</HTML>