Re: [xsl] Text Table with sorting

Subject: Re: [xsl] Text Table with sorting
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Fri, 26 Sep 2003 09:16:17 +0100
Hi Ryan,

> However, I'm rather new to XSLT and I don't know how I would
> generate that intermediate representation. I was under the
> impression that you could only have a <xsl:sort> element under a
> <xsl:for-each> element, but upon consulting my big XML book, I see
> that you can have one under an <xsl:apply-templates> element.
>
> So my question is, where would I put the sort statement? Would I put
> it under my <xsl:apply-templates select="person"/> statement? And
> doing that would sort all the children elements of <person>
> according to their refDate attributes correct?

If you're happy using a node-set() extension function, then as David
suggested, the easiest thing is to create an intermediate result tree
fragment (using a <xsl:for-each> or <xsl:apply-templates> instruction
within a variable declaration), and then convert that to a node-set
and process it. For example:

<xsl:template match="/">
  <xsl:variable name="sorted">
    <person>
      <xsl:for-each select="person/*">
        <xsl:sort select="@refDate" order="descending" />
        <xsl:copy-of select="." />
      </xsl:for-each>
    </person>
  </xsl:variable>
  <xsl:variable name="person"
                select="exsl:node-set($sorted)/person" />
  <xsl:variable name="left" select="$person/maritalStatus" />
  <xsl:variable name="middle" select="$person/dateOfBirth" />
  <xsl:variable name="right" select="$person/religion" />
  <xsl:for-each select="$left">
    ...
  </xsl:for-each>
</xsl:template>

Note that I would create the intermediate representation using an
<xsl:for-each>, since all you're doing is copying the sorted elements,
but using <xsl:apply-templates> to do so would be perfectly reasonable
as well, if you wanted:

<xsl:template match="/">
  <xsl:variable name="sorted">
    <person>
      <xsl:apply-templates select="person/*" mode="copy">
        <xsl:sort select="@refDate" order="descending" />
      </xsl:apply-templates>
    </person>
  </xsl:variable>
  <xsl:variable name="person"
                select="exsl:node-set($sorted)/person" />
  <xsl:variable name="left" select="$person/maritalStatus" />
  <xsl:variable name="middle" select="$person/dateOfBirth" />
  <xsl:variable name="right" select="$person/religion" />
  <xsl:for-each select="$left">
    ...
  </xsl:for-each>
</xsl:template>

<xsl:template match="*" mode="copy">
  <xsl:copy-of select="." />
</xsl:template>

If you're not happy using an extension function (perhaps because you
want to ensure portability of your stylesheet across processors), then
you have to actually have two separate stylesheets for each part of
the transformation. Run the second stylesheet on the result of the
first transformation.

Cheers,

Jeni

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


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread