I have an XML document that has a series of paragraphs:
<section>
<title>Section title</title>
<p style="Body">...</p>
<p style="Body">...</p>
<p style="Note">...</p>
<p style="Body">...</p>
<p style="Body">...</p>
<p style="Warning">...</p>
<p style="Warning">...</p>
<p style="Warning">...</p>
<p style="Body">...</p>
<p style="Note">...</p>
<p style="Note">...</p>
<p style="Warning">...</p>
<p style="Body">...</p>
</section>
I want to group some paragraphs so I can apply formatting to the entire group, e.g. put them inside a div so I can put a border around them. The order of the elements has to be preserved. The paragraphs I want to group have the @style 'Note','Warning' or 'Caution'. Specifically, I want to group them only if two or more paragraphs of the same @ style are adjacent to each other.
<section>
<title>Section title</title>
<p style="Body">...</p>
<p style="Body">...</p>
<p style="Note">...</p>
<p style="Body">...</p>
<p style="Body">...</p>
<div>
<p style="Warning">...</p>
<p style="Warning">...</p>
<p style="Warning">...</p>
</div>
<p style="Body">...</p>
<div>
<p style="Note">...</p>
<p style="Note">...</p>
</div>
<p style="Warning">...</p>
<p style="Body">...</p>
</section>
I'm having trouble with the for-each-group instruction:
<xsl:for-each-group select="*" group-adjacent="@stylename">
(wrap in div here)
This gives me an error because the title element does not have a @stylename
attribute.
I can't do for-each-group select="p"
because then the title element is not processed at all.
How do I process all elements in the section, but group only the paragraphs by their @stylename
?
What error are you getting? I'm assuming it's something like:
An empty sequence is not allowed as the @group-adjacent attribute of xsl:for-each-group
This is because (from the spec):
[ERR XTTE1100] It is a type error if the result of evaluating the group-adjacent expression is an empty sequence or a sequence containing more than one item, unless composite="yes" is specified.
Try changing:
group-adjacent="@style"
to:
group-adjacent="normalize-space(@style)"
Example:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" expand-text="yes">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="section">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:for-each-group select="*" group-adjacent="normalize-space(@style)">
<xsl:choose>
<xsl:when test="current-grouping-key()=('Warning','Caution','Note') and count(current-group()) > 1">
<div>
<xsl:apply-templates select="current-group()"/>
</div>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>