Obviously my understandig of how grouping in XSLT 2 works is not good enough. I´m sure that the approach with xsl:for-each-group
with group-adjacent
as attribute is right. However, I dont get the wanted result.
I want to group several adjacent elements in my XML source. The elements are identified through attribute values of a descendant element. I need to wrap them with a new element (e.g. p div="lernz"
). Sometimes these elements appear as neighbours, sometimes not.
I did not get the right result with my stylesheet. Sometimes the element before the first item of what I think should be a group is matched. But in my results so far every single item of what I think is a group is wrapped. Where is the mistake? Any help is greatly appreciated.
XML Input
<wx:sect>
<w:p>
<w:pPr w:val = 'Lern'/>
</w:p>
<w:p>
<w:pPr w:val = 'Lern'/>
</w:p>
<w:p>
<w:pPr w:val = 'Merk'/>
</w:p>
<w:p>
<w:pPr w:val = 'Lern'/>
</w:p>
<w:p>
<w:pPr w:val = 'Merk'/>
</w:p>
</w:sect>
Desired Output
<wx:sect>
<p div="wrapper-lernz">
<w:p>
<w:pPr w:val = 'Lern'/>
</w:p>
<w:p>
<w:pPr w:val = 'Lern'/>
</w:p>
</p>
<w:p>
<w:pPr w:val = 'Merk'/>
</w:p>
<p div="wrapper-lernz">
<w:p>
<w:pPr w:val = 'Lern'/>
</w:p>
</p>
<w:p>
<w:pPr w:val = 'Merk'/>
</w:p>
</w:sect>
My Stylesheet (part of it)
<xsl:template match="//w:p[w:pPr[@w:val]]">
<xsl:for-each-group select="current()" group-adjacent="//@w:val = 'Lern">
<p div="wrapper-lernz">
<xsl:value-of select="current-group()"/>
</p>
</xsl:for-each-group>
</xsl:template>
Your template matches w:p
, but if you want to group adjacent elements, you should be matching the parent w:sect
tag. By doing xsl:for-each-group select="current()"
you are trying to group a single element.
To handle only putting the "lern" elements in a container tag, you should group-adjacent= on the the "w:val" value, and then have an xsl:choose
to decide whether to add a parent tag.
Try this template:
<xsl:template match="//w:sect[w:p[w:pPr/@w:val]]">
<xsl:copy>
<xsl:for-each-group select="w:p" group-adjacent="w:pPr/@w:val">
<xsl:choose>
<xsl:when test="current-grouping-key() = 'Lern'">
<p div="wrapper-lernz">
<xsl:copy-of select="current-group()"/>
</p>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
(Note it also does xsl:copy-of
instead of xsl:value-of
as xsl:value-of
just returns the text value of a node, not the node itself)