I have an XML file that look like this and I\'m trying to wrap \"Para_bb\" node that are adjacent to each other with a div.
One way to do this in XSLT 1.0 is to have a template that matches the first occurrence of each Para_bb element in a group
<xsl:template match="Para_bb[not(preceding-sibling::*[1][self::Para_bb])]">
Then you would call a new template, with a mode specified, just on this first element
<p>
<xsl:apply-templates select="." mode="div" />
</p>
Then, in the template matching Para_bb with the mode specified, you would copy the element, and select the next sibling, but only if it is another Para_bb
<xsl:template match="Para_bb" mode="div">
<xsl:call-template name="identity" />
<xsl:apply-templates select="following-sibling::*[1][self::Para_bb]" mode="div"/>
</xsl:template>
(Where the named template being called is the standard identity template)
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="Para_bb[not(preceding-sibling::*[1][self::Para_bb])]">
<div class="blackBox">
<xsl:apply-templates select="." mode="div" />
</div>
</xsl:template>
<xsl:template match="Para_bb" />
<xsl:template match="Para_a">
<p>
<xsl:apply-templates select="@*|node()"/>
</p>
</xsl:template>
<xsl:template match="Para_bb" mode="div">
<xsl:call-template name="identity" />
<xsl:apply-templates select="following-sibling::*[1][self::Para_bb]" mode="div"/>
</xsl:template>
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
You can define a key as follows:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="group" match="Para_bb[preceding-sibling::*[1][self::Para_bb]]" use="generate-id(preceding-sibling::Para_bb[not(preceding-sibling::*[1][self::Para_bb])][1])"/>
<xsl:template match="Root">
<body>
<xsl:apply-templates/>
</body>
</xsl:template>
<xsl:template match="Para_a">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="Para_bb[preceding-sibling::*[1][self::Para_bb]]"/>
<xsl:template match="Para_bb[not(preceding-sibling::*[1][self::Para_bb])]">
<div class="blackBox">
<xsl:copy-of select=". | key('group', generate-id())"/>
</div>
</xsl:template>
</xsl:stylesheet>
That transforms
<Root>
<Para_a></Para_a>
<Para_a></Para_a>
<Para_bb>1</Para_bb>
<Para_bb>2</Para_bb>
<Para_bb>3</Para_bb>
<Para_bb>4</Para_bb>
<Para_a></Para_a>
<Para_bb>5</Para_bb>
<Para_bb>6</Para_bb>
<Para_a></Para_a>
<Para_a></Para_a>
<Para_bb>7</Para_bb>
</Root>
into
<body>
<p/>
<p/>
<div class="blackBox">
<Para_bb>1</Para_bb>
<Para_bb>2</Para_bb>
<Para_bb>3</Para_bb>
<Para_bb>4</Para_bb>
</div>
<p/>
<div class="blackBox">
<Para_bb>5</Para_bb>
<Para_bb>6</Para_bb>
</div>
<p/>
<p/>
<div class="blackBox">
<Para_bb>7</Para_bb>
</div>
</body>