Here is an XSLT 2.0 stylesheet using for-each-group
in a recursive function (I prefer that to a named template with XSLT 2.0):
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs mf">
<xsl:param name="prefix" as="xs:string" select="'h'"/>
<xsl:param name="suffix" as="xs:string" select="'-title'"/>
<xsl:output method="html" version="4.0" indent="yes"/>
<xsl:function name="mf:group" as="node()*">
<xsl:param name="items" as="node()*"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:for-each-group select="$items" group-starting-with="p[@name = concat($prefix, $level, $suffix)]">
<xsl:choose>
<xsl:when test="not(self::p[@name = concat($prefix, $level, $suffix)])">
<xsl:apply-templates select="current-group()"/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="h{$level}">
<xsl:apply-templates select="."/>
<xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:function>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="body">
<xsl:copy>
<xsl:sequence select="mf:group(*, 1)"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When I apply that stylesheet with Saxon 9 to the input
<body>
<p name="h-title" other="main">Introduction</p>
<p name="h1-title" other="other-h1">XSLT and XQuery</p>
<p name="h2-title" other=" other-h2">XSLT</p>
<p name="">
<p1 name="bold"> XSLT is used to write stylesheets.</p1>
</p>
<p name="h2-title" other="other-h2">XQuery</p>
<p name="">
<p1 name="bold"> XQuery is used to query XML databases.</p1>
</p>
<p name="h3-title" other="other-h3">XQuery and stylesheets</p>
<p name="">
<p1 name="bold"> XQuery is used to query XML databases.</p1>
</p>
<p name="h1-title" other="other-h1">XSLT and XQuery</p>
<p name="h2-title" other=" other-h2">XSLT</p>
</body>
I get the result
<body>
<p name="h-title" other="main">Introduction</p>
<h1>
<p name="h1-title" other="other-h1">XSLT and XQuery</p>
<h2>
<p name="h2-title" other=" other-h2">XSLT</p>
<p name="">
<p1 name="bold"> XSLT is used to write stylesheets.</p1>
</p>
</h2>
<h2>
<p name="h2-title" other="other-h2">XQuery</p>
<p name="">
<p1 name="bold"> XQuery is used to query XML databases.</p1>
</p>
<h3>
<p name="h3-title" other="other-h3">XQuery and stylesheets</p>
<p name="">
<p1 name="bold"> XQuery is used to query XML databases.</p1>
</p>
</h3>
</h2>
</h1>
<h1>
<p name="h1-title" other="other-h1">XSLT and XQuery</p>
<h2>
<p name="h2-title" other=" other-h2">XSLT</p>
</h2>
</h1>
</body>
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…