Search code examples
xmlxpathxsltxqueryxslt-2.0

How to mearge first & last 'xref' element value


We required the first 'xref' element as it with label/attributes and concat the label of the last 'xref' with first one. And rest other 'xref' will be drop off, Can anyone look into that and suggest?

XML Input:

<?xml version="1.0" encoding="UTF-8"?>
<xref-group>
<xref id="SL116633052-196250" scope="external" type="pdf" format="pdf"
    href="Images/1166_1.pdf">Maintenance Update 2017-21</xref>
<xref id="SL116633052-196250" scope="external" type="pdf" format="pdf"
    href="Images/1166_2.pdf">Maintenance Update 2017-22</xref>
<xref id="SL116633052-196250" scope="external" type="pdf" format="pdf"
    href="Images/1166_3.pdf">Maintenance Update 2017-23</xref>
<xref id="SL116633052-196250" scope="external" type="pdf" format="pdf"
    href="Images/1166_4.pdf">Maintenance Update 2017-24</xref>
</xref-group>

Expected Output:

<xref id="SL116633052-196250" scope="external" type="pdf" format="pdf" href="Images/1166_1.pdf">

Maintenance Update 2017-21 through Maintenance Update 2017-24

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" exclude-result-prefixes="xs" version="2.0">

<xsl:output encoding="UTF-8" indent="yes" method="xml"/>

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

<xsl:template match="xref-group/xref">
    <xsl:if test="not(preceding-sibling::xref)">
        <xsl:copy-of select="not(preceding-sibling::xref)"/>
    </xsl:if>
    <xsl:text> through </xsl:text>
    <xsl:if test="not(following-sibling::xref)">
        <xsl:copy-of select="not(following-sibling::xref)"/>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

Reference URL : https://xsltfiddle.liberty-development.net/eixh2wW/1


Solution

  • You have not specified which output you expect for an xref-group that does not have the range format. The following templates deal with the range case, defined as all xref children having the same id attribute (your question is silent about what exactly constitutes a range):

    <xsl:template match="xref-group[count(xref) > 1 and
                                    not(xref/@id != xref/@id)]/xref"/>
    <xsl:template match="xref-group[count(xref) > 1 and
                                    not(xref/@id != xref/@id)]/xref[1]"
                  priority="1">
      <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:value-of select="."/> through <xsl:value-of select="following-sibling::xref[last()]"/>
      </xsl:copy>
    </xsl:template>