Question

I need to find duplicate nodes (identified by ID) and if such nodes exist, then I need to update the id of one of them. Will appreciate if someone can let me know how to do it based on xpath or xsl.

example xml:

<music>
    <title id="1"/>
    <title id="2"/>
    <title id="1"/>
</music>

The first and third node have the same ID. So, the id of the third is changed to '3'. I need to change it to the following:

<music>
  <title id="1"/>
  <title id="2"/>
  <title id="3"/>
</music>
Was it helpful?

Solution

Please try the following template:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:template match="music">
        <xsl:copy>
            <xsl:for-each select="*">
                <xsl:element name="{name()}">
                    <xsl:attribute name="id">
                        <xsl:choose>
                            <xsl:when test="preceding::*/@id=current()/@id">
                                <xsl:value-of select="generate-id()"/>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:value-of select="@id"/>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:attribute>
                    <xsl:apply-templates/>
                </xsl:element>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

OTHER TIPS

Usually, the purpose of an ID is to uniquely identify elements. If so, it is insignificant what the actual ID string is - as long as there are no duplicates.

Therefore, the easiest approach to your problem is to number all title elements consistently, as remarked already by @michael.hor257k. This can be done using either position() or xsl:number.

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="/music">
      <xsl:copy>
         <xsl:apply-templates/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="title">
      <xsl:copy>
         <xsl:attribute name="id">
            <xsl:number/>
         </xsl:attribute>
      </xsl:copy>
   </xsl:template>

</xsl:stylesheet>

Output

<?xml version="1.0" encoding="UTF-8"?>
<music>
    <title id="1"/>
    <title id="2"/>
    <title id="3"/>
</music>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top