How to use XSLT to create distinct values

An XSLT 1.0 solution that uses key and the generate-id() function to get distinct values:

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

<xsl:key name="product" match="/items/item/products/product/text()" use="." />

<xsl:template match="/">

  <xsl:for-each select="/items/item/products/product/text()[generate-id()
                                       = generate-id(key('product',.)[1])]">
    <li>
      <xsl:value-of select="."/>
    </li>
  </xsl:for-each>

</xsl:template>

</xsl:stylesheet>

Here's an XSLT 1.0 solution that I've used in the past, I think it's more succinct (and readable) than using the generate-id() function.

  <xsl:template match="/">           
    <ul> 
      <xsl:for-each select="//products/product[not(.=preceding::*)]">
        <li>
          <xsl:value-of select="."/>
        </li>   
      </xsl:for-each>            
    </ul>
  </xsl:template>

Returns:

<ul xmlns="http://www.w3.org/1999/xhtml">
  <li>laptop</li>
  <li>charger</li>
  <li>headphones</li>
</ul>

You don't want "output (distinct-values)", but rather "for-each (distinct-values)":

<xsl:template match="/">              
  <xsl:for-each select="distinct-values(/items/item/products/product/text())">
    <li>
      <xsl:value-of select="."/>
    </li>
  </xsl:for-each>
</xsl:template>

I came to this problem while working with a Sitecore XSL rendering. Both the approach that used key() and the approach that used the preceding axis performed very slowly. I ended up using a method similar to key() but that did not require using key(). It performs very quickly.

<xsl:variable name="prods" select="items/item/products/product" />
<xsl:for-each select="$prods">
  <xsl:if test="generate-id() = generate-id($prods[. = current()][1])">
    <xsl:value-of select="." />
    <br />
  </xsl:if>
</xsl:for-each>