Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Counter inside xsl:for-each loop

Tags:

loops

xml

xslt

How to get a counter inside xsl:for-each loop that would reflect the number of current element processed.
For example my source XML is

<books>
    <book>
        <title>The Unbearable Lightness of Being </title>
    </book>
    <book>
        <title>Narcissus and Goldmund</title>
    </book>
    <book>
        <title>Choke</title>
    </book>
</books>

What I want to get is:

<newBooks>
    <newBook>
        <countNo>1</countNo>
        <title>The Unbearable Lightness of Being </title>
    </newBook>
    <newBook>
        <countNo>2</countNo>
        <title>Narcissus and Goldmund</title>
    </newBook>
    <newBook>
        <countNo>3</countNo>
        <title>Choke</title>
    </newBook>
</newBooks>

The XSLT to modify:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">
        <newBooks>
            <xsl:for-each select="books/book">
                <newBook>
                    <countNo>???</countNo>
                    <title>
                        <xsl:value-of select="title"/>
                    </title>
                </newBook>
            </xsl:for-each>
        </newBooks>
    </xsl:template>
</xsl:stylesheet>

So the question is what to put in place of ???. Is there any standard keyword or do I simply must declare a variable and increment it inside the loop?

As the question is pretty long I should probably expect one line or one word answer :)

like image 279
kristof Avatar asked Sep 18 '08 15:09

kristof


People also ask

How do you add a counter in XSLT?

XSLT is a functional language, not a procedural language, so you can't declare a counter. You can use xsl:number to get the position of the current node in its parent, if that helps. You can coerce a string to a number by using the XPath number() function.

What is the correct syntax of for each in XSLT?

The <xsl:for-each> element selects a set of nodes and processes each of them in the same way. It is often used to iterate through a set of nodes or to change the current node. If one or more <xsl:sort> elements appear as the children of this element, sorting occurs before processing.

What is xsl Cdata?

A CDATA element can be used to present formatted data or an XML document on its own. The problem is that the XSLT processor will normally strip any leading and trailing whitespace, as well as carriage returns from an output XML document – unless instructed otherwise…

What is the use of for each in XSLT?

Remarks. The <xsl:for-each> element establishes the context for iteration. The XSLT transformation instructions within this loop are to be applied to the selected nodes.


5 Answers

position(). E.G.:

<countNo><xsl:value-of select="position()" /></countNo>
like image 93
redsquare Avatar answered Oct 07 '22 06:10

redsquare


Try inserting <xsl:number format="1. "/><xsl:value-of select="."/><xsl:text> in the place of ???.

Note the "1. " - this is the number format. More info: here

like image 29
m_pGladiator Avatar answered Oct 07 '22 05:10

m_pGladiator


Try:

<xsl:value-of select="count(preceding-sibling::*) + 1" />

Edit - had a brain freeze there, position() is more straightforward!

like image 21
Luke Bennett Avatar answered Oct 07 '22 05:10

Luke Bennett


You can also run conditional statements on the Postion() which can be really helpful in many scenarios.

for eg.

 <xsl:if test="(position( )) = 1">
     //Show header only once
    </xsl:if>
like image 44
Arun Arangil Avatar answered Oct 07 '22 07:10

Arun Arangil


    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">
        <newBooks>
                <xsl:for-each select="books/book">
                        <newBook>
                                <countNo><xsl:value-of select="position()"/></countNo>
                                <title>
                                        <xsl:value-of select="title"/>
                                </title>
                        </newBook>
                </xsl:for-each>
        </newBooks>
    </xsl:template>
</xsl:stylesheet>
like image 24
Santiago Cepas Avatar answered Oct 07 '22 07:10

Santiago Cepas