user2863560
user2863560

Reputation: 11

<xsl:number> reset numbering

I have an XML file with a list of items with two different qualities and I need to create an HTML output that list the items in the two categories with a numbering sequence that start with a on both. I cannot find a solution. Here are the files I created so far:

XML

<?xml version="1.0" encoding="UTF-8"?>
<refrigerator>
<item>
<quality>Good</quality>
<item_name>eggs</item_name>
</item>
<item>
<quality>Good</quality>
<item_name>chess</item_name>
</item>
<item>
<quality>Good</quality>
<item_name>soda</item_name>
</item>
<item>
<quality>Bad</quality>
<item_name>chicken meat</item_name>
</item>
<item>
<quality>Bad</quality>
<item_name>spinach</item_name>
</item>
<item>
<quality>Bad</quality>
<item_name>potatoes</item_name>
</item>
</refrigerator>

XSL

<table width="100%" border="1">
<tr>
<td>
<strong>These are the good items in the refrigerator/strong>
<xsl:for-each select="refrigerator/item">
<xsl:if test="quality = 'Good'">
<strong><xsl:number format="a) " value="position()"/></strong>
<xsl:value-of select="item_name"/>
</xsl:if>
</xsl:for-each>

, <strong>and these are the bad ones/strong>
<xsl:for-each select="refrigerator/item">
<xsl:if test="quality = 'Bad'">
<strong><xsl:number format="a) " value="position()"/></strong>
<xsl:value-of select="item_name"/>
</xsl:if>
</xsl:for-each>


. Some more text over here.</td>
</tr>
</table>

HTML

These are the good items in the refrigerator:a) eggs b) chess c) soda , and these are the bad ones:d) chicken meat e) spinach f) potatoes . Some more text over here.

OUTPUT needed

These are the good items in the refrigerator:a) eggs b) chess c) soda , and these are the bad ones:a) chicken meat b) spinach c) potatoes . Some more text over here.

Any help is greatly appreciate it.

Regards.

A.

Upvotes: 1

Views: 898

Answers (2)

Tomalak
Tomalak

Reputation: 338326

Either: Use <xsl:for-each> correctly.

<xsl:template match="refrigerator">
  <table width="100%" border="1">
    <tr>
      <td>
        <strong>These are the good items in the refrigerator</strong>

        <xsl:for-each select="item[quality = 'Good']">
          <strong><xsl:number format="a) " value="position()"/></strong>
          <xsl:value-of select="item_name" />
        </xsl:for-each>

        <xsl:text>, <xsl:text>
        <strong>and these are the bad ones</strong>

        <xsl:for-each select="item[quality = 'Bad']">
          <strong><xsl:number format="a) " value="position()"/></strong>
          <xsl:value-of select="item_name" />
        </xsl:for-each>

        <xsl:text>. Some more text over here.</xsl:text>
      </td>
    </tr>
  </table>
</xsl:template>

Or, don't repeat yourself and don't use <xsl:for-each> at all.

<xsl:template match="refrigerator">
  <table width="100%" border="1">
    <tr>
      <td>
        <strong>These are the good items in the refrigerator</strong>

        <xsl:apply-templates select="item[quality = 'Good']" mode="numbered" />

        <xsl:text>, <xsl:text>
        <strong>and these are the bad ones</strong>

        <xsl:apply-templates select="item[quality = 'Bad']" mode="numbered" />

        <xsl:text>. Some more text over here.</xsl:text>
      </td>
    </tr>
  </table>
</xsl:template>

<xsl:template match="item" mode="numbered">
  <div>
    <strong><xsl:number format="a) " value="position()"/></strong>
    <xsl:value-of select="item_name" />
  </div>
</xsl:template>

Or, and this is even more preferred, use HTML numbered lists. Output <ol> and <li> and style them via CSS, instead of hard-coding list numbers in your output.

Upvotes: 1

Ian Roberts
Ian Roberts

Reputation: 122414

Your problem is that position() is sensitive to exactly what list of nodes you're currently for-eaching over. Instead of

<xsl:for-each select="refrigerator/item">
  <xsl:if test="quality = 'Good'">

put the test in the for-each select expression

<xsl:for-each select="refrigerator/item[quality = 'Good']">

and similarly for the "Bad" case.

As Tomalak suggests you can save repeating the same code in the two cases by moving it to a separate template and using apply-templates instead of for-each.

Upvotes: 1

Related Questions