This is a following up question to question to \"Select all of an element between the current element and the next of the current element\". Even If I\'m not sure if creatin
Here is a generic solution that will work for any heading depth:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="kChildHeader"
match="/*/*[starts-with(local-name(), 'heading_')]"
use="generate-id(preceding-sibling::*
[local-name() =
concat('heading_',
substring-after(local-name(current()), '_') - 1
)][1]
)"/>
<xsl:key name="kChildItem"
match="/*/*[not(starts-with(local-name(), 'heading_'))]"
use="generate-id(preceding-sibling::*
[starts-with(local-name(), 'heading_')][1])"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="heading_1" />
</xsl:copy>
</xsl:template>
<xsl:template match="*[starts-with(local-name(), 'heading_')]">
<xsl:copy>
<xsl:apply-templates select="key('kChildHeader', generate-id()) |
key('kChildItem', generate-id())"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When run on your sample input, this produces:
<root>
<heading_1>
<para>...</para>
<list_1>...</list_1>
<heading_2>
<para>...</para>
<heading_3>
<para>...</para>
<list_1>...</list_1>
</heading_3>
</heading_2>
<heading_2>
<para>...</para>
<footnote>...</footnote>
</heading_2>
</heading_1>
<heading_1>
<para>...</para>
<list_1>...</list_1>
<heading_2>
<para>...</para>
<list_1>...</list_1>
<list_2>...</list_2>
<heading_3>
<para>...</para>
</heading_3>
</heading_2>
<heading_2>
<para>...</para>
<footnote>...</footnote>
</heading_2>
</heading_1>
</root>
Here my current solution
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="headerLevel_txt">
<heading name="__none__" level="0"/>
<heading name="heading_1" level="1"/>
<heading name="heading_2" level="2"/>
<heading name="heading_3" level="3"/>
</xsl:variable>
<xsl:variable name="headerLevel" select="exsl:node-set($headerLevel_txt)" />
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" >
<xsl:with-param name="ch" select="h1" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="heading_1" />
</xsl:copy>
</xsl:template>
<xsl:template match="heading_1 | heading_2 | heading_3" >
<xsl:param name="previousheaader" select="'__none__'" />
<xsl:variable name="endOfLevel" >
<xsl:call-template name="endOfLevel">
<xsl:with-param name="currentheaader" select="name()" />
<xsl:with-param name="previousheaader" select="$previousheaader" />
</xsl:call-template>
</xsl:variable>
<xsl:if test ="$endOfLevel != 'end'" >
<section>
<title>
<xsl:value-of select="normalize-space(.)"/>
</title>
<!-- following siblings including next heading -->
<xsl:variable name="fsinh" select="following-sibling::*[
generate-id( preceding-sibling::*
[
name() = 'heading_1' or name() = 'heading_2' or name() = 'heading_3'
][1]
) = generate-id(current()) ]" />
<xsl:apply-templates select="$fsinh[ position()!=last()]" >
<xsl:with-param name="previousheaader" select="name()" />
</xsl:apply-templates>
<!-- following siblings heading same as next -->
<xsl:variable name="fshsan" select="following-sibling::*[
name() = name($fsinh[last()]) and
generate-id( preceding-sibling::*
[
name() = name(current())
][1]
) = generate-id(current()) ]" />
<xsl:apply-templates select="$fshsan" >
<xsl:with-param name="previousheaader" select="name()" />
</xsl:apply-templates>
</section>
</xsl:if>
</xsl:template>
<xsl:template name="endOfLevel">
<xsl:param name ="currentheaader"/>
<xsl:param name ="previousheaader"/>
<!-- The previous heading ends if the current has an higher level (smaller level number)-->
<xsl:variable name ="cl" select="number($headerLevel/heading[@name=$currentheaader]/@level)"/>
<xsl:variable name ="pl" select="number($headerLevel/heading[@name=$previousheaader]/@level)"/>
<xsl:if test ="$cl < $pl">end</xsl:if>
</xsl:template>
</xsl:stylesheet>
It will generate the following output:
<root>
<section>
<title>Section 1</title>
<para>...</para>
<list_1>...</list_1>
<section>
<title>Section 1.1</title>
<para>...</para>
<section>
<title>Section 1.1.1</title>
<para>...</para>
<list_1>...</list_1>
</section>
</section>
<section>
<title>Section 1.2</title>
<para>...</para>
<footnote>...</footnote>
</section>
</section>
<section>
<title>Section 2</title>
<para>...</para>
<list_1>...</list_1>
<section>
<title>Section 2.1</title>
<para>...</para>
<list_1>...</list_1>
<list_2>...</list_2>
<section>
<title>Seciton 2.1.1</title>
<para>...</para>
</section>
</section>
<section>
<title>Section 2.2</title>
<para>...</para>
<footnote>...</footnote>
</section>
</section>
</root>