XSL : Select distinct values (xPATH 1.0)

2014-01-28
Laurent Bientz

Imagine an XML stream composed of a collection of the same family (eg staff), each staff node has N skills and you want to know XSL distinct values ​​of all skills.

<?xml version="1.0" encoding="UTF-8"?>
<root>
||t||<View>
||t||||t||<wandiz>
||t||||t||||t||<staff>
||t||||t||||t||||t||<id>1</id>
||t||||t||||t||||t||<name>Laurent Bientz</name>
||t||||t||||t||||t||<skills>
||t||||t||||t||||t||||t||<skill>PHP5</skill>
||t||||t||||t||||t||||t||<skill>MySQL5</skill>
||t||||t||||t||||t||||t||<skill>XML</skill>
||t||||t||||t||||t||||t||<skill>XSL</skill>
||t||||t||||t||||t||||t||<skill>xPATH</skill>
||t||||t||||t||||t||</skills>
||t||||t||||t||</staff>
||t||||t||||t||<staff>
||t||||t||||t||||t||<id>2</id>
||t||||t||||t||||t||<name>Florian Collot</name>
||t||||t||||t||||t||<skills>
||t||||t||||t||||t||||t||<skill>PHP5</skill>
||t||||t||||t||||t||||t||<skill>Admin sys</skill>
||t||||t||||t||||t||</skills>
||t||||t||||t||</staff>
||t||||t||||t||<staff>
||t||||t||||t||||t||<id>3</id>
||t||||t||||t||||t||<name>Kevin Lancien</name>
||t||||t||||t||||t||<skills>
||t||||t||||t||||t||||t||<skill>HTML5</skill>
||t||||t||||t||||t||||t||<skill>CSS3</skill>
||t||||t||||t||||t||||t||<skill>Mootools</skill>
||t||||t||||t||||t||</skills>
||t||||t||||t||</staff>
||t||||t||||t||<staff>
||t||||t||||t||||t||<id>5</id>
||t||||t||||t||||t||<name>Jacques De Lamballerie</name>
||t||||t||||t||||t||<skills>
||t||||t||||t||||t||||t||<skill>PHP5</skill>
||t||||t||||t||||t||||t||<skill>MySQL5</skill>
||t||||t||||t||||t||||t||<skill>jQuery</skill>
||t||||t||||t||||t||</skills>
||t||||t||||t||</staff>
||t||||t||||t||<!-- ... -->
||t||||t||</wandiz>
||t||</View>
</root>

With xPATH 2.0, just use the function distinct-values():

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl" xmlns="http://www.w3.org/1999/xhtml">
    <xsl:template name="showSkills">
||t||||t||<ul>
||t||||t||||t||<xsl:for-each select="distinct-values(//skill)">
||t||||t||||t||||t||<li><xsl:value-of select="." /></li>
||t||||t||||t||</xsl:for-each>
||t||||t||</ul>
||t||</xsl:template>
</xsl:stylesheet>

With xPATH 1.0, the task is a bit more difficult, it must be based on sibling:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl" xmlns="http://www.w3.org/1999/xhtml">
    <xsl:template name="showSkills">
||t||||t||<ul>
||t||||t||||t||<xsl:for-each select="//skill[not(preceding::skill/. = .)]">
||t||||t||||t||||t||<li><xsl:value-of select="." /></li>
||t||||t||||t||</xsl:for-each>
||t||||t||</ul>
||t||</xsl:template>
</xsl:stylesheet>

 

Angie Menegay - 2015-05-18 19:56:04
Thanks for the example!
Marty - 2016-05-17 06:15:59
Did you mean to have :
version="1.0"
in your first example?
Chetan Naik - 2018-02-06 12:26:05
Thanks a lot. It worked With xPATH 1.0.
Thibaut - 2018-12-07 00:21:52
Merci beaucoup Laurent, j'ai bien galéré avant de trouver ta solution :)

Comment

USER EXPERIENCE

Wandi invites you to discover a new approach to navigating a website...
Are you ready?

Launch the experience