Re: [xsl] Numbering Grouped Child Elements

Subject: Re: [xsl] Numbering Grouped Child Elements
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Wed, 31 Jan 2001 12:54:56 +0000
Hi Jake,

> I'm able to group the elements so that the output looks like this:
>
> Complete the following field(s):
>         User
>         Password
> Click OK.
> Complete the following field(s):
>         Item Number
>
> I used the following XSLT to accomplish that:
[snip]

I don't know which processor you're using, but when I try your XSLT
with Saxon, I get:

Complete the following fields:
         User
         Password
Click OK.
         Item Number

So I don't think that the XSLT you provided gives the grouping you
want anyway.
         
> Now, I need to number the groups so that the output looks like this:
>
> 1.  Complete the following field(s):
>         User
>         Password
> 2.  Click OK.
> 3.  Complete the following field(s):
>         Item Number
>
> Is this possible using <xsl:number/>? Or do I need to seek some
> other solution?

xsl:number is really designed for numbering things according to their
position in the source XML. That isn't particularly what you want to
do here - you're after their position in the result tree.  You *can*
use xsl:number to do this, but it may not be worth it...

Basically, you want to have numbered instructions for (a) any
Button_Click elements and (b) any Data_Entry elements that aren't
immediately preceded by a Data_Entry element. The latter is the
trickier to do, but you can find out whether the immediately preceding
element is a Data_Entry element with the test:

  preceding-sibling::*[1][self::Data_Entry]

So, if the current node is the Steps element, you can get a node set
of the relevant Button_Click and Data_Entry elements with:

  Button_Click |
  Data_Entry[not(preceding-sibling::*[1][self::Data_Entry])]

You could apply templates to these elements:

<xsl:template match="Steps">
   <table>
      <xsl:apply-templates
         select="Button_Click |
                 Data_Entry[not(preceding-sibling::*[1][self::Data_Entry])]" />
   </table>
</xsl:template>

In that case, their position() is the number that you're after and
each of the templates has to generate the relevant row(s).  Again,
the Button_Click elements are easier to deal with:

<xsl:template match="Button_Click">
   <tr>
      <td><xsl:value-of select="position()" />.</td>
      <td>Click <xsl:apply-templates select="Button_Image" />.</td>
      <td />
   </tr>
</xsl:template>

For the Data_Entry elements, the stylesheet design so far means you'll
only ever have a template applied to the Data_Entry element (in this
default mode) if it's the first one in a data entry group. You can get
the others in the group by recursing over them, applying templates in
a different mode to give the names of the fields.

<xsl:template match="Data_Entry">
   <tr>
      <td><xsl:value-of select="position()" />.</td>
      <td colspan="2">Complete the following fields:</td>
   </tr>
   <xsl:apply-templates select="." mode="field-name" />
</xsl:template>

<xsl:template match="Data_Entry" mode="field-name">
   <tr>
      <td />
      <td colspan="2">
         <span class="Field_Name">
            <xsl:value-of select="Field_Name" />
         </span>
      </td>
   </tr>
   <xsl:apply-templates
      select="following-sibling::*[1][self::Data_Entry]"
      mode="field-name" />
</xsl:template>

If you wanted to take advantage of xsl:number's formatting facilities,
then you can do something like:

  <xsl:number value="position()" format="I." />

instead of:

  <xsl:value-of select="position()" />
  
to get the sequence I., II., III., and so on rather than 1, 2, 3.

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