CroALa DokuWiki

z:xslt-number

XSLT: number elements consecutively across sections, but not across chapters

Problem

Imagine a book with structure like this:

Chapter 1
      Section 1
         Paragraph 1
         Paragraph 2
         Paragraph 3
      Section 2
         Paragraph 1
         Paragraph 2
Chapter 2
      Section 1
         Paragraph 1
         Paragraph 2
      Section 2
         Paragraph 1
         Paragraph 2   
         Paragraph 3

If an XML document is structured like this, how do we number paragraphs consecutively, disregarding sections, but in chapters; i. e. how do we achieve this:

Chapter 1
      Section 1
         Paragraph 1
         Paragraph 2
         Paragraph 3
      Section 2
         Paragraph 4
         Paragraph 5
Chapter 2
      Section 1
         Paragraph 1
         Paragraph 2
      Section 2
         Paragraph 3
         Paragraph 4 
         Paragraph 5

XML

In other words, we want to transform this XML document:

<book>
<chapter>
  <section>
    <paragraph/>
    <paragraph/>
    <paragraph/>
  </section>
  <section>
    <paragraph/>
    <paragraph/>
  </section>
</chapter>
<chapter>
  <section>
    <paragraph/>
    <paragraph/>
  </section>
  <section>
    <paragraph/>
    <paragraph/>
    <paragraph/>
  </section>
</chapter>
</book>

Into this:

<book>
<chapter>
  <section>
    <paragraph n="1"/>
    <paragraph n="2"/>
    <paragraph n="3"/>
  </section>
  <section>
    <paragraph n="4"/>
    <paragraph n="5"/>
  </section>
</chapter>
<chapter>
  <section>
    <paragraph n="1"/>
    <paragraph n="2"/>
  </section>
  <section>
    <paragraph n="3"/>
    <paragraph n="4"/>
    <paragraph n="5"/>
  </section>
</chapter>
</book>

Solution

To achieve this, we transform the document with the following XSLT stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method = "xml" indent="yes" omit-xml-declaration="no" /> 
    <!-- consec: copy everything, number only the paragraph elements, 
    consecutively in chapters, disregard sections -->
    <!-- must include the identity template -->
    <xsl:include href="copy.xsl"/>
    <xsl:template match="//paragraph">
             <xsl:element name="{local-name()}">
                 <xsl:attribute name="n">
<xsl:value-of select="count(preceding::section/paragraph) + 
count(preceding-sibling::paragraph) - 
count(preceding::chapter/section/paragraph) + 1"/>
                 </xsl:attribute>
                 <xsl:apply-templates/>
             </xsl:element>
    </xsl:template> 
</xsl:stylesheet>

It takes some time to run, but it works.

z/xslt-number.txt · Last modified: 2015/05/22 19:56 by njovanovic