1

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

Community
  • 1
  • 1
mido
  • 77
  • 2
  • 7
  • It looks like you made edits to your question 18 minutes after I had already answered it. Is there something unsatisfactory about my answer? If you need to have the elements' tags separated like that, it can be done, but the output in my answer is semantically equivalent to what you have there. – JLRishe Mar 21 '13 at 17:30

2 Answers2

1

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>
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • Thanks for your answer. It works great. Now I want to know how can I apply rules on the specific nodes. for example I was using this ` ` and ` ` etc.. Can I apply this method on existed code? – mido Mar 22 '13 at 09:32
  • for Now I'm using to .xsl one for the duplication removal and the other for my output files – mido Mar 22 '13 at 09:58
  • @mido, Please, ask your new question as a ... *new* SO question. The comments format isn't good for exchanging code. – Dimitre Novatchev Mar 22 '13 at 14:28
0

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>
JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • Thanks for your answer. It works great. Now I want to know how can I apply rules on the specific nodes. for example I was using this ` ` and ` ` etc.. Can I apply this method on existed code? – mido Mar 22 '13 at 09:32