I have a set of sequential nodes that must be enclosed into a new element. Example:
<root>
<c>cccc</c>
<a gr="g1">aaaa</a> <b gr="g1">1111</b>
<a gr="g2">bbbb</a> <b gr="g2">2222</b>
</root>
that must be enclosed by fold
tags, resulting (after XSLT) in:
<root>
<c>cccc</c>
<fold><a gr="g1">aaaa</a> <b gr="g1">1111</b></fold>
<fold><a gr="g2">bbbb</a> <b gr="g2">2222</b></fold>
</root>
So, I have a "label for grouping" (@gr
) but not imagine how to produce correct fold tags.
I am trying to use the clues of this question, or this other one... But I have a "label for grouping", so I understand that my solution not needs the use of key()
function.
My non-general solution is:
<xsl:template match="/">
<root>
<xsl:copy-of select="root/c"/>
<fold><xsl:for-each select="//*[@gr='g1']">
<xsl:copy-of select="."/>
</xsl:for-each></fold>
<fold><xsl:for-each select="//*[@gr='g2']">
<xsl:copy-of select="."/>
</xsl:for-each></fold>
</root>
</xsl:template>
I need a general solution (!), looping by all @gr and coping (identity) all context that not have @gr... perhaps using identity transform.
Another (future) problem is to do this recursively, with fold of foldings.
In XSLT 1.0 the standard technique to handle this sort of thing is called Muenchian grouping, and involves the use of a key that defines how the nodes should be grouped and a trick using
generate-id
to extract just the first node in each group as a proxy for the group as a whole.This achieves the grouping you're after, but just like your non-general solution it doesn't preserve the indentation and the whitespace text nodes between the
a
andb
elements, i.e. it will give youNote that if you were able to use XSLT 2.0 then the whole thing becomes one
for-each-group
: