Re: [xsl] How to use xsl:key and xsl:sort?

Subject: Re: [xsl] How to use xsl:key and xsl:sort?
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Fri, 15 Feb 2002 07:29:49 +0000
Hi Cihan,

> 1- List content of <answer> in the order they appear in XML and format
> it in alphabetical order
> A,B,C,D.....
>
> A.Perform axial 4i/8i scans in all detector matrix configurations.
> B.Determine the channel(s) affected within the row(s).
> C.Determine the row(s) affected.
> D.Review system error log.

You can do this by iterating over the answer elements in document
order (which is the default order that you get if you don't do any
sorting):

  <xsl:for-each select="answer">
    <xsl:apply-templates />
  </xsl:for-each>

To get the alphabetical numbering, you can use xsl:number with a
format pattern of "A.". You could use either the position of the
answer element within the original XML document, or the position of
the answer element in the list you're processing at the moment to give
you the number. In this situation I'd use the latter, since it's
easier for the XSLT processor to work out:

  <xsl:for-each select="answer">
    <xsl:number value="position()" format="A." />
    <xsl:apply-templates />
  </xsl:for-each>

> 2- then, by looking at the @item-id order I want to list the correct
> order for the answers, and that would be
>
> D, B, A, C

Right, this time you want to iterate over the answer elements in an
order other than document order - specifically you want to sort them
based on their item-id attribute (alphabetically). So you need an
xsl:sort that selects the item-id attribute as the source of the sort
key:

  <xsl:for-each select="answer">
    <xsl:sort select="@item-id" />
    ...
  </xsl:for-each>

Then you want to get the letter associated with that answer element
from the first list, in other words its number based on the position
of the answer element in the original document as opposed to its
position in the (sorted) list that you're processing at the moment. To
do that, you need to use xsl:number's number-generating side as well
as its formatting side. In practice, that just means leaving out the
value attribute this time:

  <xsl:for-each select="answer">
    <xsl:sort select="@item-id" />
    <xsl:number format="A" />
    ...
  </xsl:for-each>

And then you want to add commas between the various letters that
you've generated, which you can do with an xsl:if that tests whether
the answer element you're processing is the last in the list:

  <xsl:for-each select="answer">
    <xsl:sort select="@item-id" />
    <xsl:number format="A" />
    <xsl:if test="position() != last()">, </xsl:if>
  </xsl:for-each>

> 3- and finally list the corrcet answers with @item-id and answer content
>
> D.Review system error log.
> B.Determine the channel(s) affected within the row(s).
> A.Perform axial 4i/8i scans in all detector matrix configurations.
> C.Determine the row(s) affected.

This is the same as the previous xsl:for-each, except that this time
you need to output the result of applying templates to the answer
(i.e. its value) as well as the number:

  <xsl:for-each select="answer">
    <xsl:sort select="@item-id" />
    <xsl:number format="A." />
    <xsl:apply-templates />
  </xsl:for-each>

I hope that helps,

Jeni

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


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


Current Thread