Re: [xsl] One Strange Problem

Subject: Re: [xsl] One Strange Problem
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Fri, 7 May 2004 12:01:27 +0100
Hi Myee,

> I have a xsl:param called sortby, which I change to the value of
> SortVal using javascript in the HTML page.

By default, the param is set to the string 'DateVal' -- in other
words, it holds the name of the element by which you want to sort.

[Actually, you're setting it to a result tree fragment whose string
value is 'DateVal'. If you want a variable or parameter to hold a
string, you should set it with the select attribute, as in:

<xsl:param name="sortby" select="'DateVal'" />
<xsl:param name="datatype" select="'number'" />

This is better because it means the processor doesn't have to build
any nodes to set these parameters.]

> So I want to sort each viewentry by $sortval, however I don't really
> have any idea what I am doing.

The normal way to do this is to select the child element of the
elements that you're sorting whose name is equal to the parameter
$sortby, as in:

  <xsl:for-each select="viewentry">
    <xsl:sort select="*[name() = $sortby]"
              data-type="{$datatype}" />
    ...
  </xsl:for-each>

Note that the things that you want to sort are the <viewentry>
elements. In your current code, you're saying that each <viewentry>
element should create a <div> element and then selecting its <DateVal>
element to be sorted -- since each <viewentry> element has only one
<DateVal> element, there's no point sorting it.

Also, I've assumed that the $datatype parameter is supplying the
datatype of the thing that you want to sort by.

> Additionally I need to sort by date and I am aware there is no way
> to sort by date, so I made somthing up.

It's a shame that DateVal doesn't use a format for dates that can be
easily sorted (e.g. the ISO format YYYY-MM-DD) as this does complicate
things a little.

You can do a variation on what you're doing at the moment, using a
<xsl:choose> to test whether $sortby is 'DateVal' and doing something
special if it is. Note that if your options are exclusive then it's
better to use an <xsl:choose> than a series of <xsl:if>s, only one of
which can be true:

<xsl:template match="viewentries">
  <div class="child" id="Sheet Entry">
    <table class="standard" cellspacing="0" cellpadding="0">
      <xsl:choose>
        <xsl:when test="$sortby = 'DateVal'">
          <xsl:apply-templates select="viewentry">
            <xsl:sort select="substring(DateVal, 7, 4)" />
            <xsl:sort select="substring(DateVal, 4, 2)" />
            <xsl:sort select="substring(DateVal, 1, 2)" />
          </xsl:apply-templates>
        </xsl:when>
        <xsl:otherwise>
          <xsl:apply-templates select="viewentry">
            <xsl:sort select="*[name() = $sortby]"
                      data-type="{$datatype}" />
          </xsl:apply-templates>
        </xsl:otherwise>
      </xsl:choose>
      ...
    </table>
  </div>
</xsl:template>

Note that the first <xsl:sort> when sorting by DateVal needs to select
the entire four digits of the year, not just the first two (you had
"substring(., 7, 2)").

In the above, I've used <xsl:apply-templates> to apply templates to
the <viewentry> elements. This enables you to have the same code
used to transform the <viewentry> elements. Just have a template
that matches <viewentry> elements and does the appropriate thing with
them:

<xsl:template match="viewentry">
  <tr>
    ...
  </tr>
</xsl:template>

Cheers,

Jeni

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

Current Thread