tags:

views:

169

answers:

3

I have an XSLT transformation with several nested <xsl:for-each> and <xsl:apply-templates>.

Now i need to number the nodes at the end of this for-each and apply-templates. Everything I tried just numbered the iterations on an level of for-each (e.q. 1,2,3,4,1,2,1,2,3,4 but I need 1,2,3,4,5,6,7,8,9,10)

(I'm pretty inexperienced with XSLT, but attempted to solve this problem with different variants of <xsl:number> and position().)

test.xml

<A>
    <B>
        <C/>
        <C/>
        <C/>
        <C/>
    </B>
    <B>
        <C/>
        <C/>
    </B>
</A>

text.xsl:

<xsl:template match="A">
    <xsl:for-each select="B">
        <xsl:for-each select="C">
            <xsl:number/>,
        </xsl:for-each>
    </xsl:for-each>
</xsl:template>

test.out

1,2,3,4,1,2,

I would like to have

1,2,3,4,5,6

EDIT: This example is to simple, it works with <xsl:number level="any" />. I first have to make a better example

+3  A: 
<xsl:number value="count(preceding::C) + 1"/><xsl:if test="following::C">,</xsl:if>

(or something similar) should do it.

hcayless
+1 Very nice ... only the commas are missing - how would i test for the very last C element?
Filburt
Added conditional comma above
hcayless
Thanks! Way cool!
Filburt
A: 

You can increment the variable:

<xsl:template match="A">
    <xsl:variable name="count" select="1"/>
    <xsl:for-each select="B">
        <xsl:for-each select="C">
            <xsl:variable name="count" select="$count + 1"/>
            <xsl:value-of select="count" />,
        </xsl:for-each>
    </xsl:for-each>
</xsl:template>
antyrat
This results in an error: "The variable or parameter 'count' was duplicated within the same scope."
Filburt
@antyrat: There is no such thing as "incrementing a variable" in XSLT. All variables are constant, you can never change their values.
Tomalak
+1  A: 

Try:

<xsl:template match="A/B/C">
  <xsl:value-of select="position()" />
</xsl:template>

position() always returns the position of the current node in the batch of nodes that is being processed at the moment. Your solution:

<xsl:template match="A">
  <xsl:for-each select="B">
    <xsl:for-each select="C">
      <xsl:number/>,
    </xsl:for-each>
  </xsl:for-each>
</xsl:template>

Processes four batches of nodes:

  • One batch of <A> nodes. They go from position 1 to 1.
  • One batch of <B> nodes. They go from position 1 to 2.
  • Two Batches of <C> nodes. They go from position 1-4 and 1-2

While my solution processes, by selecting them directly:

  • One batch of <C> nodes. They go from position 1-6
Tomalak
Nice solution. I see i have still to learn a lot about xslt...
nuriaion