Re: [xsl] Reformatting

Subject: Re: [xsl] Reformatting
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Fri, 11 May 2001 08:17:08 +0100
Hi Greg,

> I am trying to use XSLT format the output abbreviating ranges of
> channels. The above would ideally be formatted as:
>
>       1-4,10-13,24

This is a grouping problem.  Since it's all in sorted order already,
then you could just use a flat method where you apply templates to
everything and work out from each ch element what you should output.
Dan's already shown you a version of that method, although it could be
simplified to:

<xsl:template match="ch">
   <xsl:variable name="prev" select="preceding-sibling::*[1]"/>
   <xsl:variable name="next" select="following-sibling::*[1]"/>
   <xsl:choose>
      <!-- if next is not in sequence (end of group)... -->
      <xsl:when test=". != $next - 1">
         <!-- ...if part of sequence, add a '-' -->
         <xsl:if test=". = $prev + 1">-</xsl:if>
         <!-- ...give the value of the ch -->
         <xsl:value-of select="." />
         <!-- ...add a comma if there's a following ch -->
         <xsl:if test="$next">, </xsl:if>
      </xsl:when>
      <!-- if prev is not in sequence (start of group)... -->
      <xsl:when test=". != $prev + 1">
         <!-- ...give the value of the ch -->
         <xsl:value-of select="." />
      </xsl:when>
   </xsl:choose>
</xsl:template>

You could also use a grouping method where you only apply templates to
the first node in each group.  You can work out whether they're the
first node in the group by looking at whether they have a preceding
sibling whose value is one less than theirs:

<xsl:template match="T1">
   <xsl:apply-templates select="ch[. != preceding-sibling::*[1] + 1]" />
</xsl:template>

The ch-matching template will only be applied to nodes that are the
first in the group.  You can work out the last of that group by
finding the next following sibling whose first following sibling is
not one more than it is:

<xsl:template match="ch">
   <xsl:value-of select="." />
   <xsl:variable name="next"
                 select="following-sibling::*
                            [. != following-sibling::*[1] - 1][1]" />
   <xsl:if test="$next">
      <xsl:text />-<xsl:value-of select="$next" />
   </xsl:if>
   <xsl:if test="position() != last()">, </xsl:if>
</xsl:template>

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