Remove duplicate node set based on element tag is empty

334 views Asked by At
***This is my input xml coming from source.***

<?xml version="1.0" encoding="UTF-8" ?>
<exampleElement xmlns="http://www.example.org">
<element1>
  <Id>123</Id>
  <Name>Imag</Name>
  <Status>active</Status>
  <EndDate/>
</element1>
<element1>
  <Id>888</Id>
  <Name>Preci</Name>
  <Status>active</Status>
  <EndDate/>
</element1>    
<element1>
  <Id>123</Id>
  <Name>Imag</Name>
  <Status>terminated</Status>
  <EndDate>2016-12-10</EndDate>
</element1>
<element1>
<Id>143</Id>
<Name>kilok</Name>
<Status>terminated</Status>
<EndDate>2016-11-10</EndDate>
</element1>
</exampleElement>

In above input data two sets duplicated with different value.Where ID=123 element node has two records with EndDate value and with out EndDate.

**I want out put in this below format where one record set 
from duplicates with EndDate tag empty.**

<?xml version = '1.0' encoding = 'UTF-8'?>
<ns1:exampleElement xmlns:ns1="http://www.example.org">
<ns1:element1>
  <ns1:Id>888</ns1:Id>
  <ns1:Name>Preci</ns1:Name>
  <ns1:Status>active</ns1:Status>
  <ns1:EndDate/>
</ns1:element1>
<ns1:element1>
  <ns1:Id>123</ns1:Id>
  <ns1:Name>Imag</ns1:Name>
  <ns1:Status>active</ns1:Status>
  <ns1:EndDate/>
</ns1:element1>
<ns1:element1>
  <ns1:Id>143</ns1:Id>
  <ns1:Name>Kilok</ns1:Name>
  <ns1:Status>terminated</ns1:Status>
  <ns1:EndDate>2016-11-10</ns1:EndDate>
  </ns1:element1>
</ns1:exampleElement>

Please find the below my xslt where this will give unique records,but I want to get the unique record based on value.

<xsl:template match="/">
<ns1:exampleElement>
  <xsl:for-each select="/ns1:exampleElement/ns1:element1[not(ns1:Id=following::ns1:Id)]">
    <ns1:element1>
      <ns1:Id>
        <xsl:value-of select="./ns1:Id"/>
      </ns1:Id>
      <ns1:Name>
        <xsl:value-of select="./ns1:Name"/>
      </ns1:Name>
      <ns1:Status>
        <xsl:value-of select="./ns1:Status"/>
      </ns1:Status>
      <ns1:EndDate>
        <xsl:value-of select="./ns1:EndDate"/>
      </ns1:EndDate>
    </ns1:element1>
  </xsl:for-each>
</ns1:exampleElement>

because from the source system will receive the user Active record in first set and terminated record in second set but we need to forward only active record to target system.Please help on this.

1

There are 1 answers

4
Tim C On BEST ANSWER

You were given a link to an article to Muenchian Grouping in comments, which explains the approach to take. It involves first define a key to match the elements you want to group (where ns1 is a namespace prefix bound to the namespace URI)

<xsl:key name="elements" match="ns1:element1" use="ns1:Id" /> 

Then, to get the distinct ones (or rather, the first occurrence of elements for each possible value of Id), you would do this...

<xsl:for-each select="ns1:element1[generate-id() = generate-id(key('elements', ns1:Id)[1])]" />

And to access all the elements in the group, do this..

<xsl:for-each select="key('elements', ns1:Id)">

Try this XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns1="http://www.example.org">  
   <xsl:key name="elements" match="ns1:element1" use="ns1:Id" /> 

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

   <xsl:template match="/">
        <xsl:copy>
            <xsl:for-each select="*/ns1:element1[generate-id() = generate-id(key('elements', ns1:Id)[1])]">
                <xsl:for-each select="key('elements', ns1:Id)">
                    <xsl:sort select="ns1:EndDate" />
                    <xsl:if test="position() = 1">
                        <xsl:apply-templates select="." />
                    </xsl:if>
                </xsl:for-each>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>

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

If you really wanted to output the XML with ns1: prefix (although it really shouldn't make a difference), try this instead

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns1="http://www.example.org">  
   <xsl:key name="elements" match="ns1:element1" use="ns1:Id" /> 

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

   <xsl:template match="/">
        <ns1:exampleElement>
            <xsl:for-each select="*/ns1:element1[generate-id() = generate-id(key('elements', ns1:Id)[1])]">
                <xsl:for-each select="key('elements', ns1:Id)">
                    <xsl:sort select="ns1:EndDate" />
                    <xsl:if test="position() = 1">
                        <xsl:apply-templates select="." />
                    </xsl:if>
                </xsl:for-each>
            </xsl:for-each>
        </ns1:exampleElement>
    </xsl:template>

    <xsl:template match="*" priority="2">
        <xsl:element name="ns1:{local-name()}">
            <xsl:apply-templates select="@*|node()"/>
        </xsl:element>
    </xsl:template>

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