IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

XSL/XSLT/XPATH XML Discussion :

groupement + fonction distinct-values() [XSLT 1.0]


Sujet :

XSL/XSLT/XPATH XML

  1. #1
    Membre habitué
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2010
    Messages
    212
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2010
    Messages : 212
    Points : 184
    Points
    184
    Par défaut groupement + fonction distinct-values()
    Bonsoir,
    soit le doc votes.xml :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    <?xml version="1.0"?>
    <Votes>											
    <Ville nom="Cachan" dept="94">
    <Bureau num="1">
    <Candidat nom="Toto" voix="3398"/><Candidat nom="Dupont" voix="6589"/>
    </Bureau>
    <Bureau num="2">
    <Candidat nom="Toto" voix="5645"/><Candidat nom="Dupont" voix="4090"/>
    </Bureau>
    </Ville>
    <Ville nom="L’Hay" dept="94">
    <Bureau num="1">
    <Candidat nom="Toto" voix="2067"/><Candidat nom="Dupont" voix="4089"/>
    </Bureau>
    </Ville>
    <Ville nom="Bagneux" dept="92">
    <Bureau num="1">
    <Candidat nom="Toto" voix="4723"/><Candidat nom="Dupont" voix="5167"/>
    </Bureau>
    </Ville>
    </Votes>
    Question:
    Écrivez un programme XSLT qui calcule la somme des voix pour chacun des candidats. Le résultat de la transformation donnera le document :
    <Votes>
    <Candidat nom="Toto">15833</Candidat>
    <Candidat nom="Dupont">19935</Candidat>
    </Votes>

    Mon essai:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    ...
    xsl:template match="Votes">
    <votes>
    	<xsl:for-each select="Ville/Bureau/Candidat">
    	<xsl:if test="not(@nom=following::Candidat/@nom)">
    	<xsl:variable name="nom" select="@nom"/>
    	<candidat nom="{@nom}"><xsl:value-of select="sum(//Candidat[@nom=$nom]/@voix)"/> </candidat>
    	</xsl:if>
    	</xsl:for-each>
    	</votes>
    	</xsl:template>
    ...
    çà marche tés bien. je veux une autre solution utilisant la fonction:
    distinct-values ()
    merci d'avance

  2. #2
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    distinct-values() c'est une fonction pour XSLT 2.0, pas 1.0
    Mais ok, très bien, il suffit d'utiliser du 2.0.

    Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    <root>
      <a>Hello</a>
      <a>Bonjour</a>
      <a>Hello</a>
    </root>
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <xsl:template match="/">
      <root>
        <xsl:for-each select="distinct-values(//a)">
          <a>
            <xsl:value-of select="."/>
          </a>
        </xsl:for-each>
      </root>
    </xsl:template>
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre habitué
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2010
    Messages
    212
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2010
    Messages : 212
    Points : 184
    Points
    184
    Par défaut
    voici un code utilisant la fonction: distinct-values:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="2.0">
        <xsl:template match="Votes">
            <votes>
            <xsl:for-each select="distinct-values(//Candidat/@nom)">
                <candidat nom= "{.}">
                   <xsl:value-of select="sum(//Candidat[@nom=.]/@voix)" />
                </candidat>
            </xsl:for-each>
            </votes>
        </xsl:template>
    </xsl:stylesheet>
    érreur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     ...
    Description: Leading '/' cannot select the root node of the tree containing the context item: the context item is an atomic value
    Emplacement de début: 8:0
    URL: http://www.w3.org/TR/xpath20/#ERRXPTY0020

  4. #4
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Marrant. C'est vrai que moi j'aurais utilisé xsl:for-each-group au lieu de distinct-values(), et donc le problème se poserait pas. Je m'attendais pas à ce que XPath 2.0 nous fasse un coup pareil.

    Il existe peut-être une solution triviale, mais si ce n'est pas le cas, il suffit de mettre l'ensemble des candidats dans une variable, avant de commencer le for-each. Comme ça on peut y accéder avec cette variable au lieu de //

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <xsl:variable name="candidats" select="//Candidat"/>
    Reste à régler le problème qui apparaît ensuite. La solution est la même.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Expert confirmé
    Avatar de Loceka
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    2 276
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 2 276
    Points : 4 845
    Points
    4 845
    Par défaut
    Citation Envoyé par win_ubuntu Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <xsl:value-of select="sum(//Candidat[@nom=.]/@voix)" />
    Je doute que cette partie-là fasse ce que tu souhaites :
    Là tu testes que l'attribut nom de l'élément Candidat a la même valeur que le contenu texte de ce même élément Candidat.

    Toi ce que tu veux c'est le comparer à l'attribut nom actuellement sélectionné. Pour ça, il faut que tu passes soit par une variable, soit par la fonction XSL current():
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <xsl:value-of select="sum(//Candidat[@nom=current()]/@voix)" />

  6. #6
    Membre habitué
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2010
    Messages
    212
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2010
    Messages : 212
    Points : 184
    Points
    184
    Par défaut
    merci infiniment les gars; voila la solution, çà marche trés bien:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="2.0">
        <xsl:template match="Votes">
            <votes>
                <xsl:variable name="candidats" select="//Candidat"/>
                <xsl:for-each select="distinct-values(//Candidat/@nom)">
                    <candidat nom= "{.}">
                        <xsl:value-of select="sum($candidats[@nom=current()]/@voix)" />
                    </candidat>
                </xsl:for-each>
            </votes>
        </xsl:template>
    </xsl:stylesheet>
    mais remarquez vous que le parser a accepté cette ligne :
    dans la première solution, et l'a refusé dans la deuxième!.

  7. #7
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Citation Envoyé par win_ubuntu Voir le message
    mais remarquez vous que le parser a accepté cette ligne :
    dans la première solution, et l'a refusé dans la deuxième!.
    Ben oui, pour la raison indiquée.
    Un XPath s'évalue toujours à partir du contexte en cours.
    Lorsqu'on fait un for-each, à l'intérieur de la boucle, le contexte en cours est l'élément pour lequel on fait la boucle. C'est pour ça qu'on peut utiliser le . dans <candidat nom= "{.}">.

    Or un XPath qui commence par / signifie "commence déjà par remonter au document," et par "le document" on veut dire "le document qui contient le contexte en cours."
    Si le for-each se fait sur un ensemble d'éléments du document,comme par exemple //machin , ça marche très bien.
    Mais dans le cas de distinct-values(), on ne sélectionne pas des éléments. On extrait la valeur des éléments, sous forme de strings, et on en renvoie la liste d'occurrences uniques. Une string n'appartient à aucun document, comme il le dit c'est un atome. Et donc commencer par / n'a pas de sens si le contexte est une simple string, obtenue avec distinct-values().


    La solution correcte à ce besoin est <xsl:for-each-group>, et non pas distinct-values(). Ainsi le problème ne se poserait pas.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  8. #8
    Expert confirmé
    Avatar de Loceka
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    2 276
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 2 276
    Points : 4 845
    Points
    4 845
    Par défaut
    Citation Envoyé par thelvin Voir le message
    dans le cas de distinct-values(), on ne sélectionne pas des éléments. On extrait la valeur des éléments, sous forme de strings, et on en renvoie la liste d'occurrences uniques. Une string n'appartient à aucun document, comme il le dit c'est un atome. Et donc commencer par / n'a pas de sens si le contexte est une simple string, obtenue avec distinct-values().
    J'aurais jamais pensé à ça.
    C'est d'autant plus bizarre qu'en sortie (du distinct-values) on a quand même des noeuds (attributs dans le cas actuel), qui eux sont bien rattaché à un document.

    Note que je ne doûte pas de ton explication mais ce comportement de XSL me semble pour le moins étrange.

  9. #9
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Citation Envoyé par Loceka Voir le message
    J'aurais jamais pensé à ça.
    C'est d'autant plus bizarre qu'en sortie (du distinct-values) on a quand même des noeuds (attributs dans le cas actuel), qui eux sont bien rattaché à un document.
    Non, ce sont probablement des xs:string. En tout cas ce sont des xs:anyAtomicType, toujours le cas avec distinct-values(). Les nœuds sont convertis en xs:anyAtomicType en fonction de leur type XML Schema, ou xs:string s'ils n'en ont pas.

    Citation Envoyé par Loceka Voir le message
    Note que je ne doûte pas de ton explication mais ce comportement de XSL me semble pour le moins étrange.
    Il est fort dommage que des valeurs XPath atomiques ne soient pas considérées comme faisant partie du document sur lequel s'exécute la transformation, c'est sûr -_-°. Déjà que pour les éléments faisant partie d'un autre document, je trouve le comportement de // douteux...
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [XPATH] distinct values
    Par yannick29000 dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 19/08/2010, 15h11
  2. appel d'une fonction dans value
    Par ASP.net dans le forum Général Dotnet
    Réponses: 4
    Dernier message: 03/07/2008, 15h08
  3. [xslt 1.0] - distinct value sur un attribut
    Par jacquesh dans le forum XSL/XSLT/XPATH
    Réponses: 1
    Dernier message: 30/10/2007, 07h38
  4. 4D Open for 4D:pb OP Distinct Values
    Par Kendael dans le forum 4D
    Réponses: 3
    Dernier message: 20/04/2007, 12h43
  5. Fonction DISTINCT ne fonctionne pas sur une date
    Par cramouille dans le forum Access
    Réponses: 5
    Dernier message: 25/10/2006, 15h42

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo