xmlxsltduplicatesxml-parsing

Removing Xml nodes with a match in the sibling nodes


Trying to remove Xml nodes with a match in the sibling nodes text using xslt

my xml looks like below

    <?xml version="1.0" encoding="UTF-8"?>
    <root xmlns:map="http://www.w3.org/2005/xpath-functions/map">
    <row>
        <Name>Africa</Name>
    </row>
    <row>
        <Name>USA</Name>
    </row>
    <row>
        <Name>Mexico</Name>
    </row>
    <row>
        <Name>Canada</Name>
    </row>
    <row>
        <Name>Malaysia</Name>
    </row>
    <row>
        <Name>Africa</Name>
    </row>
    <row>
        <Name>Mexico</Name>
    </row>
    <row>
        <Name>Bangladesh</Name>
    </row>
    </root>`

and the output i need is below

   
    `<?xml version="1.0" encoding="UTF-8"?>
     <root >
     <row>
      <Name>USA</Name>
     </row>
     <row>
      <Name>Canada</Name>
     </row>
     <row>
      <Name>Malaysia</Name>
     </row>
     <row>
      <Name>Bangladesh</Name>
     </row>
     </root>

` tried below xslt but seeing Africa and Mexico in the output xml code as well. I want these two duplicated nodes along with original nodes of the same value to be removed altogether from the output

    `<xsl:stylesheet version="2.0" 
       <xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
      <xsl:strip-space elements="*"/>
       <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
     </xsl:template>
    
    
     <xsl:template match="row[.=preceding-sibling::row/.]"/>
     </xsl:stylesheet>`

Tried this above xslt but still seeing Africa and Mexico nodes as well in the output.

Please help me to remove these nodes in the output .`


Solution

  • Here is one simple method:

    XSLT 2.0

    <xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:template match="/root">
        <xsl:copy>
            <xsl:for-each-group select="row" group-by="Name">
                <xsl:if test="count(current-group())=1">
                    <xsl:copy-of select="."/>
                </xsl:if> 
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>
        
    </xsl:stylesheet>
    

    Here's another:

    XSLT 1.0

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:key name="row-by-name" match="row" use="Name" />
    
    <xsl:template match="/root">
        <xsl:copy>
            <xsl:copy-of select="row[count(key('row-by-name', Name))=1]"/>
        </xsl:copy>
    </xsl:template>
        
    </xsl:stylesheet>