Voir :
<?xml version="1.0" encoding="UTF-8"?> <contacts> <contact> <prenom>Jean</prenom> <nom>Chenier</nom> </contact> <contact> <prenom>Marie</prenom> <nom>Pariseau</nom> </contact> <contact> <prenom>Jean</prenom> <nom>Poirier</nom> </contact> </contacts>On souhaite afficher la liste de toutes les personnes dans des tableaux, chaque tableau regroupant les contacts ayant un même prénom.
/contacts/contact/prenomLe résultat contiendra deux personnes ayant le prénom Jean. Pour identifier les tableaux et leur nombre, nous devons filtrer les doublons. Nous ajoutons une condition sur l'élément "contact" pour exprimer le fait que l'on ignore le contact si une personne avec le prénom du contact a été déjà rencontrée.
not(preceding::contact/prenom = prenom)Ce test utilise l'opérateur XPath "=" pour comparer deux ensembles de noeuds: l'ensemble de tous les sous éléments "prenom" des éléments "contact" précédents et l'ensemble composé de l'élément "prenom" de l'élément "contact" courant. Pour XPath, ce test est vrai si les deux ensembles ont au moins un noeud ayant une valeur commune. La condition entière est vraie si les deux ensembles n'ont pas d'élément commun. Nous pouvons l'utiliser dans les attributs "select" ou "match" :
<xsl:apply-templates select="/contacts/contact[not( preceding::contact/prenom = prenom )]"/>ou :
<xsl:variable name="prenoms-distincts" select="/contacts/contact[not( preceding::contact/prenom = prenom )]"/>
<xsl:key name="id" match="contact" use="prenom"/>Cette déclaration définit une clé dont le nom est "id", qui porte sur tous les éléments "contact" du document et qui utilise comme identifiant la valeur de leur sous-élément "prenom". Pour sélectionner la liste des éléments "contact" ayant pour prenom "Jean", nous pouvons maintenant écrire l'expression XPath :
key('id', 'Jean')Cet accès par clé est optimisé par les processeurs XSLT qui construisent une table de correspondance à la première utilisation de la clé. Cette première utilisation est donc plus lente qu'un de nos balayages répétitifs, mais les utilisations suivantes utilisent la table de correspondance et elles sont beaucoup plus rapides. Exemple:
<xsl:apply-templates select="key('id', 'Jean')"/>traite tous les éléments "contact" ayant 'Jean' comme prénom et
<xsl:apply-templates select="key('id', 'Jean')[2]"/>traitera le deuxième "contact" (dans notre cas, celui de Jean Poirier).
generate-id(key('id',prenom)) = generate-id(key('id',prenom)[1])Nous pouvons écrire alors :
/contacts/contact[generate-id(.) = generate-id(key('id', prenom)[1])]Si cette condition vous semble être assez complexe, regardez le tableau avec les valeurs exemplaires :
contact | generate-id(.) | generate-id(key('id',prenom)) |
---|---|---|
Jean Chenier | 'idcontact86585840' | 'idcontact86585840' |
Marie Pariseau | 'idcontact86350544' | 'idcontact86350544' |
Jean Poirier | 'idcontact88974024' | 'idcontact86585840' |
/contacts/contact/prenom[ count( . | key('id', prenom)[1]) = 1]Les deux variantes donnent strictement le même résultat et sont équivalentes en terme de performance. Dans les deux cas, ces expressions XPath/XSLT peuvent être utilisées dans une instruction XSLT telle que :
<xsl:apply-templates select="/contacts/contact/prenom[generate-id() = generate-id(key('id', prenom)[1])]"/>ou encore :
<xsl:variable name="prenoms-distincts" select="/contacts/contact[ count( . | key('id', prenom)[1]) = 1]"/>