Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use XSLT to create distinct values

Tags:

xslt

People also ask

What is regex in XSLT?

The regex-group() function names which matched string you want to use inside of the xsl:matching-substring element; pass it a 1 to get the first, a 2 to get the second, and so forth. The example above uses it to plug the three matched values inside new city, state, and zip elements created for the output.

What is text () in XSLT?

XSLT <xsl:text> The <xsl:text> element is used to write literal text to the output. Tip: This element may contain literal text, entity references, and #PCDATA.

What is number () in XSLT?

Definition and Usage. The <xsl:number> element is used to determine the integer position of the current node in the source. It is also used to format a number.

What is current () XSLT?

XSLT current() Function The current() function returns a node-set that contains only the current node. Usually the current node and the context node are the same.


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>

distinct-values(//product/text())