8

Input XML:

<doc>
 <section>
  <para>Paragraph 1</para>
  <para>Paragraph 2</para>
  <para>Paragraph 3</para>
 </section>
  <para>Paragraph 4</para>
  <para>Paragraph 5</para>
  <para>Paragraph 6</para>
</doc>

Required output:

<book>
<section>
  <p class="para" id="0001">Paragraph 1</p>
  <p class="para" id="0002">Paragraph 2</p>
  <p class="para" id="0003">Paragraph 3</p>
 </section>
  <p class="para" id="0004">Paragraph 4</p>
  <p class="para" id="0005">Paragraph 5</p>
  <p class="para" id="0006">Paragraph 6</p>
 </book>

I tried with following XSL but I am not getting desired output. Anyone could help me in this?

<xsl:template match="para">
    <xsl:variable name="count" select="position()"/>
    <p class="para" id="{$count}">
        <xsl:apply-templates/>
    </p>
</xsl:template>

The result I am getting is:

<p class="para" id="2">Paragraph 1</p>
<p class="para" id="4">Paragraph 2</p>
<p class="para" id="6">Paragraph 3</p>

    <p class="para" id="4">Paragraph 4</p>
    <p class="para" id="6">Paragraph 5</p>
    <p class="para" id="8">Paragraph 6</p>
Daniel Haley
  • 51,389
  • 6
  • 69
  • 95
VSe
  • 919
  • 2
  • 13
  • 29

2 Answers2

16

Here's an option that isn't using xsl:for-each or any xsl:variable's...

XML Input

<doc>
    <section>
        <para>Paragraph 1</para>
        <para>Paragraph 2</para>
        <para>Paragraph 3</para>
    </section>
    <para>Paragraph 4</para>
    <para>Paragraph 5</para>
    <para>Paragraph 6</para>
</doc>

XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="doc">
        <book>
            <xsl:apply-templates select="@*|node()"/>
        </book>
    </xsl:template>

    <xsl:template match="para">
        <p class="para" id="{format-number(count(preceding::para)+1,'0000')}">
            <xsl:apply-templates select="@*|node()"/>
        </p>
    </xsl:template>

</xsl:stylesheet>

XML Output

<book>
   <section>
      <p class="para" id="0001">Paragraph 1</p>
      <p class="para" id="0002">Paragraph 2</p>
      <p class="para" id="0003">Paragraph 3</p>
   </section>
   <p class="para" id="0004">Paragraph 4</p>
   <p class="para" id="0005">Paragraph 5</p>
   <p class="para" id="0006">Paragraph 6</p>
</book>

A second option is instead of counting preceding::para you could use xsl:number...

<xsl:template match="para">
    <p class="para">
        <xsl:attribute name="id">
            <xsl:number format="0000" level="any"/>
        </xsl:attribute>
        <xsl:apply-templates select="@*|node()"/>
    </p>
</xsl:template>
Daniel Haley
  • 51,389
  • 6
  • 69
  • 95
  • i did. if someone downvote against one up, u will get 9 (10-2). :-) – vels4j Nov 26 '12 at 09:21
  • @DimitreNovatchev - Thank you. Also, I enjoyed your blog posting about word ladders. Very interesting! – Daniel Haley Nov 26 '12 at 20:38
  • @DevNull, You are always welcome. Apologies for the messed code formatting of the blog post -- at present I haven't found a way to make WordPress format XML/XSLT code properly. – Dimitre Novatchev Nov 26 '12 at 20:44
2

Here is your required xsl

 <xsl:template match="doc">
    <book>
        <section>
            <xsl:for-each select="section/para">
                <xsl:variable name="count" select="position()"/>
                <xsl:variable name ="seq">
                    <xsl:value-of select="format-number($count,'0000')"/>
                </xsl:variable>
                <p class="para" id="{$seq}">
                    <xsl:value-of select="."/>
                </p>
            </xsl:for-each>
        </section>
        <xsl:variable name="secCount" select="count(section/para)"/>
        <xsl:for-each select="para">
            <xsl:variable name="count" select="position()"/>
            <xsl:variable name ="seq">
            <xsl:value-of select="format-number( number($count) + number($secCount),'0000')"/>
        </xsl:variable>
            <p class="para" id="{$seq}">
                <xsl:value-of select="."/>
            </p>
        </xsl:for-each>
    </book>
</xsl:template>
vels4j
  • 11,208
  • 5
  • 38
  • 63