Bala
Bala

Reputation: 68

Merge multiple elements as a single element

I need suggestions to merge multiple elements and sibling text nodes as a single element. Refer xref element in the below mentioned sample.

Input: <section><p>These pages are all about XSLT, an XML-based language <xref ref-type="bibr" rid="r1">1</xref><xref ref-type="bibr" rid="r2"/>--<xref ref-type="bibr" rid="r3">3</xref> for translating one set of XML into another set of XML, <xref ref-type="bibr" rid="r3">3</xref>, <xref ref-type="bibr" rid="r5">5</xref><xref ref-type="bibr" rid="r6"/>--<xref ref-type="bibr" rid="r7">7</xref> or into HTML. Of course, there are all sorts of other pages  <xref ref-type="bibr" rid="r1">7</xref>, <xref ref-type="bibr" rid="r3">8</xref>  around that cover XSLT. <xref ref-type="bibr" rid="r12">12</xref>, <xref ref-type="bibr" rid="r15">15</xref><xref ref-type="bibr" rid="r16"/><xref ref-type="bibr" rid="r17"/><xref ref-type="bibr" rid="r18"/><xref ref-type="bibr" rid="r19"/>--<xref ref-type="bibr" rid="r20">20</xref></p></section>

Output: <section><p>These pages are all about XSLT, an XML-based language <xref ref-type="bibr" rid="r1 r2 r3">1--3</xref> for translating one set of XML into another set of XML, <xref ref-type="bibr" rid="r3 r5 r6 r7">3, 5--7</xref> or into HTML. Of course, there are all sorts of other pages <xref ref-type="bibr" rid="r7 r8">7, 8</xref> around that cover XSLT. <xref ref-type="bibr" rid="r12 r15 r16 r17 r18 r19 r20">12, 15--20</xref></p></section>

The merge should happen only if characters (, )comma with space or ( ) space or (--) two hyphens or empty xref element (<xref ref-type="bibr" rid="r2"/>) appear inbetween xref elements.

E.g.
Input content: <xref ref-type="bibr" rid="r3">3</xref>, <xref ref-type="bibr" rid="r5">5</xref><xref ref-type="bibr" rid="r6"/>--<xref ref-type="bibr" rid="r7">7</xref>  

Expected ouput: <xref ref-type="bibr" rid="r1 r2 r3">1--3</xref>

Thanks and Regards Bala

Upvotes: 0

Views: 282

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167726

Using XSLT 2.0, you can find adjacent nodes using for-each-group select="node()" group-adjacent="boolean(self::xref | self::text()[matches(., $pattern)] so you can use an approach like

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*[xref]">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:for-each-group select="node()"
                group-adjacent="boolean(self::xref | self::text()[matches(., '^[\s\p{P}]+$')])">
                <xsl:choose>
                    <xsl:when test="current-grouping-key()">
                        <xsl:copy>
                            <xsl:copy-of select="@* except @rid"/>
                            <xsl:attribute name="rid" select="current-group()/@rid"/>
                            <xsl:value-of select="current-group()"/>
                        </xsl:copy>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:apply-templates select="current-group()"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Upvotes: 1

Related Questions