Re: [xsl] Filling gaps in a list of values

Subject: Re: [xsl] Filling gaps in a list of values
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Tue, 22 Jan 2002 13:37:04 +0000
Hi Ben,

> I'm trying to sort a set of nodes in descending order and output them with
> any gaps filled in.
>
> ie
>
> <node order="1" name="fred"/>
> <node order="4" name="bob"/>
>
> will produce
>
> order 4: bob
> order 3: no name
> order 2: no name
> order 1: fred
>
> I've tried using <xsl:for-each> but I can't seem to get hold of the
> next node to be processed to check it! I've also tried using
> <xsl:apply-templates select="node[@order]"> but the template is
> called once for every node.

You need a recursive template to count down from the highest node
order to the lowest node order. On each recursion, it will find the
node with the relevant number (if there is one) and produce the
required result. Then, if it is still greater than the lowest number,
it will call itself, with the count being one less.

<xsl:template name="countDown">
  <xsl:param name="from" select="1" />
  <xsl:param name="to" select="1" />
  <xsl:variable name="node" select="node[@order = $from]" />
  <xsl:value-of select="concat('order ', $from, ': ')" />
  <xsl:choose>
    <xsl:when test="$node">
      <xsl:value-of select="$node/@name" />
    </xsl:when>
    <xsl:otherwise>no name</xsl:otherwise>
  </xsl:choose>
  <xsl:text>&#xA;</xsl:text>
  <xsl:if test="$from > $to">
    <xsl:call-template name="countDown">
      <xsl:with-param name="from" select="$from - 1" />
      <xsl:with-param name="to" select="$to" />
    </xsl:call-template>
  </xsl:if>
</xsl:template>

[Note that if you have lots of nodes, you might find it more efficient
to retrieve them using a key instead.]

To start the process off, you need to find the highest and lowest
values for the order attributes of the nodes that you're processing.
Assuming that they're arranged in order in the first place, this might
be something like:

  <xsl:call-template name="countDown">
    <xsl:with-param name="from" select="node[last()]/@order" />
    <xsl:with-param name="to" select="node[1]/@order" />
  </xsl:call-template>

Otherwise you might have to search through them to find the ones with
the highest and lowest values; there are various methods listed in the
FAQ at http://www.dpawson.co.uk/xsl/sect2/N5121.html.

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