I'm having a problem with XSLT V1.0 with removing the duplicated nodes. I have this for entry
<?xml version="1.0" encoding="utf-8"?>
<myRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Mappings>
<Mapping fieldName="field1" >
</Mapping>
<Mapping fieldName="field1">
</Mapping>
<Mapping fieldName="field2" >
</Mapping>
<Mapping fieldName="field3" >
</Mapping>
<Mapping fieldName="field4">
</Mapping>
</Mappings>
</myRoot>
I have this XSL file
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Mappings">
<xsl:if test="not(following::Mappings[Mapping/@fieldName=current()/Mapping/@fieldName])">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
And I have the same entry XML file as result !!
How can I get rid of duplicated node () ?
I tried everything and no result :(
I tried
Removing duplicates in xml with xslt
Transform to remove duplicate and copy rest
Removing consecutive duplicates with XSLT
XSLT 1.0 textlist to individual elements and duplicate removal
......
What should I do to have this result ??
<?xml version="1.0" encoding="utf-8"?>
<myRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Mappings>
<Mapping fieldName="field1">
</Mapping>
<Mapping fieldName="field2" >
</Mapping>
<Mapping fieldName="field3" >
</Mapping>
<Mapping fieldName="field4">
</Mapping>
</Mappings>
</myRoot>
Thanks
The solution is very simple (no named templates and no use of xsl:call-template
, only two templates, completely "push style"):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kFieldNameByVal" match="@fieldName" use="."/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"Mapping[not(generate-id(@fieldName)
= generate-id(key('kFieldNameByVal', @fieldName)[1]))]"/>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<myRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Mappings>
<Mapping fieldName="field1" >
</Mapping>
<Mapping fieldName="field1">
</Mapping>
<Mapping fieldName="field2" >
</Mapping>
<Mapping fieldName="field3" >
</Mapping>
<Mapping fieldName="field4">
</Mapping>
</Mappings>
</myRoot>
the wanted, correct result is produced:
<myRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Mappings>
<Mapping fieldName="field1"/>
<Mapping fieldName="field2"/>
<Mapping fieldName="field3"/>
<Mapping fieldName="field4"/>
</Mappings>
</myRoot>
The problem here is that your template is matching Mappings
and attempting to exclude following duplicate Mappings
elements, but there are none.
In either case, following::
and preceding::
are not good ways to select distinct values in XSLT. Instead, you should use Muenchian grouping:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*" />
<xsl:key name="kMapping" match="Mapping" use="@fieldName"/>
<xsl:template match="@* | node()" name="Copy">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Mapping[generate-id() =
generate-id(key('kMapping', @fieldName)[1])]">
<xsl:call-template name="Copy" />
</xsl:template>
<xsl:template match="Mapping" />
</xsl:stylesheet>
When run on your sample input, this produces:
<myRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Mappings>
<Mapping fieldName="field1" />
<Mapping fieldName="field2" />
<Mapping fieldName="field3" />
<Mapping fieldName="field4" />
</Mappings>
</myRoot>