I read some answers here on moving nodes down/wrapping elements, but can´t figure out the solution to my problem. Here it is: I want to turn a flat document hierarchy in a "deep" hierarchy with xslt (2.0). The problem is to limit the search for siblings to a certain sibling, in my case: Search all siblings from h1 up to next h1 node.
xml-code
<root>
<h1>A heading</h1>
<para>Some text.</para>
<h2>More text</h2>
<table>Content</table>
<pic>a picture</pic>
<h1>Another heading.</h1>
<para>Some text again.</para>
<para>More text.</para>
...
</root>
Real document is much longer, there are up to five levels of headings, there is no fixed order of elements, and in real life I need to move not only the h1-sections, but also the h2-sections and so on. I´ve tried several attempts with copy-of- and similar expressions, but I´ma newbie in xslt. So how to wrap all h1-elements and its siblings up to the next h1-element with a chapter-element and h2-elements in the same way with section-elements?
Desired output is
<root>
<chapter>
<h1>A heading</h1>
<para>Some text.</para>
<section>
<h2>More text</h2>
<table>Content</table>
<pic>a picture</pic>
</section>
</chapter>
<chapter>
<h1>Another heading.</h1>
<para>Some text again.</para>
<para>More text.</para>
</chapter>
...
</root>
The method you can use is two embedded for-each-group
commands:
root
, for groups starting with h1
. h2
. One important feature of for-each-group
coupled with group-starting-with
is that when the source content does not start with the tag specified in group-starting-with
, then the "starting part" (without the specified starting tag) is the first group.
To distinguish between this "initial" group (starting actually with h1
) and groups starting with h2
, I used xsl:choose
.
So the whole script can look like below:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="root">
<xsl:copy>
<xsl:for-each-group select="*" group-starting-with="h1">
<chapter>
<xsl:for-each-group select="current-group()" group-starting-with="h2">
<xsl:choose>
<xsl:when test="name()='h1'">
<xsl:copy-of select="current-group()"/>
</xsl:when>
<xsl:otherwise>
<section>
<xsl:copy-of select="current-group()"/>
</section>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</chapter>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:transform>
For a working example see http://xsltransform.net/pNvs5w8
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.