ttdol2506
ttdol2506

Reputation: 103

Removing duplicates based on attribute values in XSLT

I have this XML code:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <A>
        <B>
            <C index="0">
                <element index="0">one</element>
                <element index="1">two</element>
                <keyElement index="1">key</keyElement >
            </C>
            <C index="0">
                <element index="0">one</element>
                <element index="1">two</element>
                <keyElement index="1">key</keyElement >
            </C>
        </B>
    </A>
</root>

and I want to remove duplicates based on index value. I am already using a key for the keyElement which I am using in the iteration.

<xsl:key name="group-by-keyElement" match="C" use="keyElement" />
<xsl:for-each select="key('group-by-keyElement', keyElement )">

In the same iteration I need to remove the duplicates so that the output shows only once the values in C.

The result wanted is this:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <A>
        <B>
            <C index="0">
                <element index="0">one</element>
                <element index="1">two</element>
                <keyElement index="1">key</keyElement >
            </C>
        </B>
    </A>
</root>

Upvotes: 0

Views: 1492

Answers (1)

Valdi_Bo
Valdi_Bo

Reputation: 30971

You wrote: I want to remove duplicates based on index value. I assume, you mean the value of index attribute in C tag.

Below you have a solution, working in both XSLT 1.0 and XSLT 2.0.

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="xml" encoding="UTF-8" indent="yes" />
  <xsl:strip-space elements="*"/>

  <xsl:key name="indexKey" match="//C[@index]" use="@index" />

  <xsl:template match="C">
    <xsl:if test="generate-id()=generate-id(key('indexKey', @index)[1])">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
    </xsl:if>
  </xsl:template>

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

The key point is template matching C tag.

The first thing to do is to check whether the id generted for the current node (generate-id()) is equal to the id generated for the first element returned by key function from key named indexKey and value of the current index attribute.

If this is the case, then:

  • Make a (shallow) copy of the current element.
  • Apply templates to the content of the current element.

Upvotes: 1

Related Questions