Reputation: 17335
I try to understand the grouping functions in XSLT 2.0. My source document is
<root>
<entry level="a" name="aaa"/>
<entry level="a" name="bbb"/>
<entry level="b" name="ccc"/>
<entry level="c" name="ddd"/>
<entry level="a" name="eee"/>
<entry level="a" name="fff"/>
<entry level="b" name="ggg"/>
</root>
and the result should be something like
<section name="aaa"/>
<section name="bbb">
<section name="ccc">
<section name="ddd" />
</section>
</section>
<section name="eee"/>
<section name="fff">
<section name="ggg" />
</section>
That is: if there is a following entry with a deeper level (b is deeper than a,...) the next section should be child of the current, if it is the same level, it should be the next sibling.
I've tried with xsl:group-by select="entry" group-by="@level"
which gives me a sensible grouping, but I don't know how to open the section to go down, if there is a down.
There is another similar question which states that "In XSLT 2.0 it would be rather easy with the new grouping functions." - it might be easy but I don't get it.
Upvotes: 2
Views: 587
Reputation: 167516
Here is an example:
<xsl:stylesheet
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"
version="2.0">
<xsl:output indent="yes"/>
<xsl:function name="mf:group" as="element(section)*">
<xsl:param name="entries" as="element(entry)*"/>
<xsl:param name="level" as="xs:string"/>
<xsl:for-each-group select="$entries" group-starting-with="entry[@level = $level]">
<section name="{@name}">
<xsl:sequence select="mf:group(current-group() except ., codepoints-to-string(string-to-codepoints($level)[1] + 1))"/>
</section>
</xsl:for-each-group>
</xsl:function>
<xsl:template match="root">
<xsl:copy>
<xsl:sequence select="mf:group(entry, 'a')"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Should work with any levels from 'a' to 'z'.
Saxon 9.4, when running above against
<root>
<entry level="a" name="aaa"/>
<entry level="a" name="bbb"/>
<entry level="b" name="ccc"/>
<entry level="c" name="ddd"/>
<entry level="a" name="eee"/>
<entry level="a" name="fff"/>
<entry level="b" name="ggg"/>
</root>
outputs
<root>
<section name="aaa"/>
<section name="bbb">
<section name="ccc">
<section name="ddd"/>
</section>
</section>
<section name="eee"/>
<section name="fff">
<section name="ggg"/>
</section>
</root>
Upvotes: 3