Reputation: 67
I have an input xml file that have multiple <b>
elements, i have to wrap all <b>
that are appearing continuously. i have written an xsl for this. it is better way to do this? also there are extra space generated during transformation after wrapping elements.
Sample Input XML
<chap>
<p><b>The</b> <b>Attorney</b> General <b>(Fees)</b><b>a</b><b>b</b><b>c</b> Determination 2012 No 110 commenced on 1 <b>July</b> <b>2012</b> <b>and</b> was repealed on <b>1</b> <b>July</b> <b>2013</b>. The Determination is yet to be amended by:</p>
</chap>
XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:guru="Self"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="b[preceding-sibling::node()[1][self::b]]
|b[preceding-sibling::node()[1][normalize-space(.) = '']][preceding-sibling::node()[2][self::b]]"/>
<xsl:template match="b">
<xsl:copy>
<xsl:apply-templates/>
<xsl:if test="following-sibling::node()[1][self::b]">
<xsl:copy-of select="guru:wrap(following-sibling::node()[1], '')"/>
</xsl:if>
<xsl:if test="following-sibling::node()[1][normalize-space(.) = '']/following-sibling::node()[1][self::b]">
<xsl:copy-of select="guru:wrap(following-sibling::node()[2], following-sibling::node()[1])"/>
</xsl:if>
</xsl:copy>
</xsl:template>
<xsl:function name="guru:wrap">
<xsl:param name="b_data"/>
<xsl:param name="space"/>
<xsl:value-of select="$space"/>
<xsl:value-of select="$b_data"/>
<xsl:if test="$b_data/following-sibling::node()[1][self::b]">
<xsl:copy-of select="guru:wrap($b_data/following-sibling::node()[1], '')"/>
</xsl:if>
<xsl:if test="$b_data/following-sibling::node()[1][normalize-space(.) = '']/following-sibling::node()[1][self::b]">
<xsl:copy-of select="guru:wrap($b_data/following-sibling::node()[2], $b_data/following-sibling::node()[1])"/>
</xsl:if>
</xsl:function>
</xsl:stylesheet>
Output
<chap>
<p><b>The Attorney</b> General <b>(Fees)abc</b> Determination 2012 No 110 commenced on 1 <b>July 2012 and</b> was repealed on <b>1 July 2013</b> . The Determination is yet to be amended by:</p>
</chap>
Desired Output
<chap>
<p><b>The Attorney</b> General <b>(Fees)abc</b> Determination 2012 No 110 commenced on 1 <b>July 2012 and</b> was repealed on <b>1 July 2013</b>. The Determination is yet to be amended by:</p>
</chap>
Thanks in Advance.
Upvotes: 0
Views: 111
Reputation: 167506
I would suggest to use for-each-group group-adjacent="self::b or self::text()[. = ' ']"
:
<xsl:template match="p">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:for-each-group select="node()" group-adjacent="self::b or self::text()[. = ' ']">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<b>
<xsl:apply-templates select="current-group()/node() | current-group()[self::text()]"/>
</b>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
https://xsltfiddle.liberty-development.net/gWmuiHU/1 shows the result, it uses XSLT 3 but for XSLT 2 you simply have to remove the xsl:mode
and keep the identity template
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
you have in your code.
Upvotes: 1