I want to group by headers, but when the structure isn't logical the sectioning stops. For example <h2> followed by <h4>. See example. I would like to see the <h4> sectioned when there is no <h3> but I can't seem to get it work. Could someone help me with that? I work with xslt 2.0.
Input:
<?xml version="1.0" encoding="UTF-8"?> <document id="21" state="Schrijven" documentTypeName="News"> <document track-changes="false" version="1"> <section> <h1>Title h1</h1> <p>Some text</p> <p/> <h2>Title h2</h2> <p>Some text</p> <p/> <h3>Title h3</h3> <p>Some text</p> <p/> <h2>Title h2</h2> <p>Some text</p> <p/> <h4>Title h4</h4> <p>Some text</p> <p/> </section> </document> </document>
Output
<html> <head> <meta charset="UTF-8"/> </head> <body data-sws-documentkey="id-00021"> <section class="level-newsitem"> <h1 class="nieuws">Title h1</h1> <p>Some text</p> <p/> <section class="level"> <h2>Title h2</h2> <p>Some text</p> <p/> <section class="level"> <h3>Title h3</h3> <p>Some text</p> <p/> </section> </section> <section class="level"> <h2>Title h2</h2> <p>Some text</p> <p/> <h4>Title h4</h4> <p>Some text</p> <p/> </section> </section> </body> </html>
Desired Output
<html> <head> <meta charset="UTF-8"/> </head> <body data-sws-documentkey="id-00021"> <section class="level-newsitem"> <h1 class="nieuws">Title h1</h1> <p>Some text</p> <p/> <section class="level"> <h2>Title h2</h2> <p>Some text</p> <p/> <section class="level"> <h3>Title h3</h3> <p>Some text</p> <p/> </section> </section> <section class="level"> <h2>Title h2</h2> <p>Some text</p> <p/> <section class="level"> <h4>Title h4</h4> <p>Some text</p> <p/> </section> </section> </section> </body> </html>
Stylesheet
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:cwc="urn:cwc" xmlns:p1="urn:p1" exclude-result-prefixes="xs cwc p1" version="2.0"> <xsl:output method="xml" indent="yes" encoding="UTF-8"/> <xsl:strip-space elements="document meta section div row"/> <xsl:variable name="DocumentKey"> <xsl:value-of select="concat('id-000', /document[1]/@id)"/> </xsl:variable> <xsl:variable name="DocSoort"> <xsl:value-of select="/document/@documentTypeName"/> </xsl:variable> <xsl:template match="document"> <html> <head> <meta charset="UTF-8"/> <xsl:if test="./meta/description"> <meta name="description"> <xsl:attribute name="content"> <xsl:value-of select="./meta/description"/> </xsl:attribute> </meta> </xsl:if> <title><xsl:value-of select="./naam"/></title> </head> <body data-sws-documentkey="{$DocumentKey}"> <xsl:choose> <xsl:when test="$DocSoort='Note'"> <xsl:apply-templates mode="Note"/> </xsl:when> <xsl:when test="$DocSoort='News'"> <xsl:apply-templates mode="News"/></xsl:when> </xsl:choose> </body> </html> </xsl:template> <xsl:template match="h1" mode="#all"> <xsl:variable name="DocSoorttitel"> <xsl:choose> <xsl:when test="$DocSoort='Note'">noteitem</xsl:when> <xsl:when test="$DocSoort='News'">newsitem</xsl:when> </xsl:choose> </xsl:variable> <xsl:variable name="count"> <xsl:value-of select="count(preceding::h1)"/> </xsl:variable> <xsl:choose> <xsl:when test="$count = 0"> <xsl:copy> <xsl:attribute name="class"> <xsl:value-of select="$DocSoorttitel"/> </xsl:attribute> <xsl:apply-templates select="@*[name()!='class']" mode="#current"/> <xsl:apply-templates mode="#current"/> </xsl:copy> </xsl:when> <xsl:otherwise> <xsl:copy> <xsl:apply-templates select="@*" mode="#current"/> <xsl:apply-templates mode="#current"/> </xsl:copy> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="naam|meta|lastmodified" mode="#all"/> <xsl:template match="*/document" mode="#all"> <xsl:choose> <xsl:when test="not(./section)"> <section> <xsl:attribute name="class"> <xsl:value-of select="lower-case(concat('sws-', $DocSoort))"/> </xsl:attribute> <xsl:call-template name="groupingheaders"/> </section> </xsl:when> <xsl:otherwise> <xsl:apply-templates mode="#current"/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="section" mode="#all"> <section> <xsl:attribute name="class"> <xsl:value-of select="lower-case(concat('level-', $DocSoort))"/> </xsl:attribute> <xsl:call-template name="groupingheaders"/> </section> </xsl:template> <xsl:template name="groupingheaders"> <xsl:choose> <xsl:when test="$DocSoort='Note'"> <xsl:for-each-group select="*" group-starting-with="div[@class = 'letop'][parent::document or parent::section]|h2[parent::document or parent::section][count(text()[normalize-space()]) > 0]"> <xsl:choose> <xsl:when test="current-group()[1]/self::div[@class = 'letop'][parent::document or parent::section]|current-group()[1]/self::h2[parent::document or parent::section][count(text()[normalize-space()]) > 0]"> <section class="level"> <xsl:call-template name="group2"/> </section> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="current-group()" mode="#current"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:when> <xsl:when test="$DocSoort='News'"> <xsl:for-each-group select="*" group-starting-with="h2[parent::document or parent::section][count(text()[normalize-space()]) > 0]"> <xsl:choose> <xsl:when test="current-group()[1]/self::h2[parent::document or parent::section][count(text()[normalize-space()]) > 0]"> <section class="level"> <xsl:call-template name="group2"/> </section> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="current-group()" mode="#current"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:when> </xsl:choose> </xsl:template> <xsl:template name="group2"> <xsl:for-each-group select="current-group()" group-starting-with="h3[parent::document or parent::section][count(text()[normalize-space()]) > 0]"> <xsl:choose> <xsl:when test="current-group()[1]/self::h3[parent::document or parent::section][count(text()[normalize-space()]) > 0]"> <section class="level"> <xsl:call-template name="group3"/> </section> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="current-group()" mode="#current"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:template> <xsl:template name="group3"> <xsl:for-each-group select="current-group()" group-starting-with="h4[parent::document or parent::section][count(text()[normalize-space()]) > 0]"> <xsl:choose> <xsl:when test="current-group()[1]/self::h4[parent::document or parent::section][count(text()[normalize-space()]) > 0]"> <section class="level"> <xsl:call-template name="group4"/> </section> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="current-group()" mode="#current"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:template> <xsl:template name="group4"> <xsl:for-each-group select="current-group()" group-starting-with="h5[parent::document or parent::section][count(text()[normalize-space()]) > 0]"> <xsl:choose> <xsl:when test="current-group()[1]/self::h5[parent::document or parent::section][count(text()[normalize-space()]) > 0]"> <section class="level"> <xsl:call-template name="group5"/> </section> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="current-group()" mode="#current"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:template> <xsl:template name="group5"> <xsl:for-each-group select="current-group()" group-starting-with="h6[parent::document or parent::section][count(text()[normalize-space()]) > 0]"> <xsl:choose> <xsl:when test="current-group()[1]/self::h6[parent::document or parent::section][count(text()[normalize-space()]) > 0]"> <section class="level"> <xsl:apply-templates select="current-group()" mode="#current"/> </section> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="current-group()" mode="#current"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:template> <xsl:template match="node()" mode="#all"> <xsl:copy> <xsl:apply-templates select="node()" mode="#current"/> </xsl:copy> </xsl:template> </xsl:stylesheet>