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>
3
  • are you getting this ? <p class="para" id="4">Paragraph 4</p> Commented Nov 26, 2012 at 7:35
  • No, 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> Commented Nov 26, 2012 at 7:39
  • Please show your output XML by editing your question Commented Nov 26, 2012 at 7:39

2 Answers 2

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>
Sign up to request clarification or add additional context in comments.

3 Comments

i did. if someone downvote against one up, u will get 9 (10-2). :-)
@DimitreNovatchev - Thank you. Also, I enjoyed your blog posting about word ladders. Very interesting!
@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.
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>

2 Comments

Experts may still simplify this xsl. I've tried up to my knowledge.
That won't work too well if there is more than one section or if the section isn't always before sibling para's.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.