Re: [xsl] Choosing different sorts

Subject: Re: [xsl] Choosing different sorts
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Thu, 15 Jul 2004 15:22:53 +0100
Hi Derek,

> I have tried, in my code to have:
>
>   <xsl:for-each select="file">
>      <xsl:choose>
>         <xsl:when test="$sort='design'"><xsl:sort
> select="name"/></xsl:when>
>         <xsl:when test="$sort='stat'"><xsl:sort
> select="status"/></xsl:when>
>         <xsl:otherwise><xsl:sort select="id"/></xsl:otherwise>   
>
>       </xsl:choose>

As has been pointed out to you, you can't have <xsl:sort> elements
wrapped in a <xsl:choose> -- they must be the first, direct, children
of <xsl:for-each>.

The difficulty, then, is to select a different thing to sort by
depending on the value of the $sort variable. You've been shown a
couple of ways to do this. Another way is:

  <xsl:for-each select="file">
    <xsl:sort select="name[$sort = 'design'] |
                      status[$sort = 'stat'] |
                      id[$sort != 'design' and $sort != 'stat']" />
    ...
  </xsl:for-each>

This selects a node-set containing the <name> element child of <file>,
but only if $sort is 'design', the <status> element, but only if $sort
is 'stat', and the <id> element, but only if $sort is neither 'design'
nor 'stat'. Since the three conditions are mutually exclusive, you end
up with a node-set containing the single node that you want.

The advantage of this method is that the paths that select the nodes
you want can be anything at all -- they don't all have to be children
of the nodes you're sorting, for example.

Of course, in XSLT 2.0, things become a lot clearer. You can use the
if expression in XPath 2.0 as follows:

  <xsl:for-each select="file">
    <xsl:sort select="if ($sort = 'design') then name
                      else if ($sort = 'stat') then status
                      else id" />
    ...
  </xsl:for-each>

Or if you prefer you can use an <xsl:choose> inside the <xsl:sort>, as
in:

  <xsl:for-each select="file">
    <xsl:sort>
      <xsl:choose>
        <xsl:when test="$sort = 'design'">
          <xsl:sequence select="name" />
        </xsl:when>
        <xsl:when test="$sort = 'stat'">
          <xsl:sequence select="status" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:sequence select="id" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:sort>
    ...
  </xsl:for-each>

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/

Current Thread