0

I have to exclude duplicated values from a single node using XSLT

ex.

<?xml version="1.0" encoding="UTF-8" ?>
<base>
<string>test1,test2,test3,test1,test4,test2,test5,</string>
</base>

The result should look like this:

<?xml version="1.0" encoding="UTF-8" ?>
<base>
string>test1,test2,test3,test4,test5,</string>
</base>

Could anyone help me with this please ?

drstonecodez
  • 317
  • 1
  • 2
  • 12

1 Answers1

0

If you're trying to do this in XSLT 1.0, You should be able to do something like this xsl: how to split strings?, and maybe using a document() function if it's supported by your processor to load the results of that into a document and then maybe use an xsl:key to get the distinct results. It's pretty convoluted though. Here is another method that avoids some of that convolution using pure XSLT 1.0: https://stackoverflow.com/a/34944992/3016153.

My preference would still be for some kind of extension for this; if you're doing this using MSXML, you could do something like the following (I'd probably prefer C# here, but JavaScript is probably more portable if you're not using MSXML):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:user="http://mycompany.com/mynamespace">
  <xsl:template match="/base/string">
    <xsl:value-of select="user:distinctSplit(string(.))" />
  </xsl:template>
  <msxsl:script language="JScript" implements-prefix="user">

   function distinctSplit(str) {
      var u = {}, a = [];
      var splt = str.split(',');
      for(var i = 0;i &lt; splt.length;i++) {
        if (u.hasOwnProperty(splt[i])) {
          continue;
        }
        a.push(splt[i]);
        u[splt[i]] = 1;
      }

      return a.join(',');
   }
 </msxsl:script>
</xsl:stylesheet>

If you're not using MSXML, you might be able to get a tokenize extension or use your processor's method of embedding JavaScript (and your processor might even support the .filter() function for arrays, which could make this code simpler - testing locally with MSXML didn't support filter() for me).

If you're using XSLT 2.0, you could use tokenize and distinct-values, something like this should work:

<xsl:for-each select="distinct-values(tokenize(/base/string, ','))" separator=",">
  <xsl:value-of select="concat(., ',')" />
</xsl:for-each>

but you might have to play with it a little as it may add extra , literals that you don't want at the end.

Community
  • 1
  • 1
Dan Field
  • 20,885
  • 5
  • 55
  • 71
  • For XSLT 2.0 it is working perfectly fine , thank You ! Is it also possible to somehow do it in XSLT 1.0 ? – drstonecodez Jan 17 '17 at 15:05
  • The first part of my answer is for XSLT 1.0 - but there's no easy/straightforward way to do it without extensions. I started playing with it and while I'm sure it's somehow possible I don't think it'd be pretty. If you found the answer helpful, consider upvoting it and marking it as accepted for future users. – Dan Field Jan 17 '17 at 15:21
  • 1
    The XSLT 2.0 suggestion can be shortened to ``, without needing to worry about extra commas at the end. – Martin Honnen Jan 17 '17 at 16:10
  • @PiotrP For an XSLT 1.0 solution, see: http://stackoverflow.com/a/34944992/3016153 – michael.hor257k Jan 17 '17 at 16:37
  • 1
    @DanField "*there's no easy/straightforward way to do it without extensions.*" Ahem. – michael.hor257k Jan 17 '17 at 16:39
  • Edited again @michael.hor257k - that's definitely better than the path I was attempting, but IMO it's still not as straight forward as using an extension... – Dan Field Jan 17 '17 at 17:00