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 :

Regrouper par elements identiques [XSLT 2.0]


Sujet :

XSL/XSLT/XPATH XML

  1. #1
    yos
    yos est déconnecté
    Membre confirmé
    Inscrit en
    Mai 2005
    Messages
    140
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 140
    Par défaut Regrouper par elements identiques
    Bonjour,
    A partir de ce 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
    <?xml version="1.0" encoding="UTF-8"?>
    <doc>
    	<spe>
    		<id>1</id>
    		<ci>a</ci>
    		<ci>b</ci>
    	</spe>
    	<spe>
    		<id>2</id>
    		<ci>a</ci>
    		<ci>b</ci>
    		<ci>c</ci>
    	</spe>
    	<spe>
    		<id>3</id>
    		<ci>a</ci>
    		<ci>b</ci>
    		<ci>d</ci>
    	</spe>
    </doc>
    j'aimerai obtenir le résultat suivant:
    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
    <?xml version="1.0" encoding="UTF-8"?>
    <doc>
    	<commun>
    		<id>1</id>
    		<id>2</id>
    		<id>3</id>
    		<ci>a</ci>
    		<ci>b</ci>
    	</commun>
    	<commun>
    		<id>2</id>
    		<ci>c</ci>
    	</commun>
    	<commun>
    		<id>3</id>
    		<ci>d</ci>
    	</commun>
    </doc>
    voici un essai d'xsl qui ne donne pas le résultat souhaité :
    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
    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    	<xsl:output method="xml" indent="yes"/>
    	<xsl:template match="/">
    		<doc>
    			<xsl:for-each-group select="//ci" group-by="text()">
    				<commun>
    					<xsl:for-each select="current-group()">
    						<id>
    							<xsl:value-of select="preceding-sibling::id"/>
    						</id>
    					</xsl:for-each>
    					<ci>
    						<xsl:value-of select="current-grouping-key()"/>
    					</ci>
    				</commun>
    			</xsl:for-each-group>
    		</doc>
    	</xsl:template>
    </xsl:stylesheet>
    Merci pour votre aide.

  2. #2
    Membre Expert Avatar de tsuji
    Inscrit en
    Octobre 2011
    Messages
    1 558
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 1 558
    Par défaut
    L'idée essentielle de ce rendrement est d'avoir les notions de séquence des valeurs distingues ci puisse prendre ("a", "b", "c", "d"), de séquence des valeurs commune à tous les spe et de séquence du reste ("c", "d"). Sans ces notions implémentées implicitement ou explicitement, on peut y avoir de difficulté comme témoignée ici. On peut faire un regroupement comme montré, on peut faire travailler directement avec des séquences de valeurs atomiques... Ma préférence n'a pas d'importance.

    Si vous voulez faire avec la notion de regroupement, on peut faire comme ça sans faisant de raffinement pas toujours nécessaire.
    Code xml : 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
    23
    24
    25
    26
    27
    28
    29
    30
    <xsl:template match="/">
        <doc>
            <commun>
                <xsl:for-each-group select="for $ci in //ci return $ci[every $spe in //spe satisfies (count($spe[ci = $ci]) ge 1)]" group-by="text()">
                    <xsl:if test="position()=1">
                        <xsl:for-each select="current-group()">
                            <id>
                                <xsl:value-of select="preceding-sibling::id"/>
                            </id>
                        </xsl:for-each>
                    </xsl:if>
                    <ci>
                        <xsl:value-of select="current-grouping-key()"/>
                    </ci>
                </xsl:for-each-group>
            </commun>
            <xsl:for-each-group select="for $ci in //ci return $ci[some $spe in //spe satisfies (count($spe/ci[. = $ci]) eq 0)]" group-by="text()">
                <commun>
                    <xsl:for-each select="current-group()">
                        <id>
                            <xsl:value-of select="preceding-sibling::id"/>
                        </id>
                    </xsl:for-each>
                    <ci>
                        <xsl:value-of select="current-grouping-key()"/>
                    </ci>
                </commun>
            </xsl:for-each-group>
        </doc>
    </xsl:template>

  3. #3
    yos
    yos est déconnecté
    Membre confirmé
    Inscrit en
    Mai 2005
    Messages
    140
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 140
    Par défaut
    Excellent, c'est parfait
    Merci beaucoup tsuji,
    Merci aussi pour les explications.

  4. #4
    yos
    yos est déconnecté
    Membre confirmé
    Inscrit en
    Mai 2005
    Messages
    140
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 140
    Par défaut
    Merci tsuji pour ton aide.
    Juste un petit souci si on ajoute un nouvel élément <ci>e</ci> comme suite:
    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
    <?xml version="1.0" encoding="UTF-8"?>
    <doc>
    	<spe>
    		<id>1</id>
    		<ci>a</ci>
    		<ci>b</ci>
    	</spe>
    	<spe>
    		<id>2</id>
    		<ci>a</ci>
    		<ci>b</ci>
    		<ci>c</ci>
    	</spe>
    	<spe>
    		<id>3</id>
    		<ci>a</ci>
    		<ci>b</ci>
    		<ci>d</ci>
    		<ci>e</ci>
    	</spe>
    </doc>
    On obtient:
    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" encoding="UTF-8"?>
    <doc>
    	<commun>
    		<id>1</id>
    		<id>2</id>
    		<id>3</id>
    		<ci>a</ci>
    		<ci>b</ci>
    	</commun>
    	<commun>
    		<id>2</id>
    		<ci>c</ci>
    	</commun>
    	<commun>
    		<id>3</id>
    		<ci>d</ci>
    	</commun>
    	<commun>
    		<id>3</id>
    		<ci>e</ci>
    	</commun>
    </doc>
    au lieu de:
    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
    <?xml version="1.0" encoding="UTF-8"?>
    <doc>
    	<commun>
    		<id>1</id>
    		<id>2</id>
    		<id>3</id>
    		<ci>a</ci>
    		<ci>b</ci>
    	</commun>
    	<commun>
    		<id>2</id>
    		<ci>c</ci>
    	</commun>
    	<commun>
    		<id>3</id>
    		<ci>d</ci>
    		<ci>e</ci>
    	</commun>
    </doc>
    Merci encore pour votre aide

  5. #5
    Membre Expert Avatar de tsuji
    Inscrit en
    Octobre 2011
    Messages
    1 558
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 1 558
    Par défaut
    Je ne sais pas si vous comprenez bien que le template je vous ai montré regroupe tous les id pour chacun de ci qui ne sont pas apparus dans tous les spe. Il a bien le mérite de lui-même. Par exemple, si la valeur c apparu dans les spe de id (2, 5, 9), il donnerait un résultat comme ça.
    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    <commun>
        <id>2</id>
        <id>5</id>
        <id>9</id>
        <ci>c</ci>
    </commun>
    et il n'est pas du tout déraisonnable qu'on veut en avoir pour ce genre de ci qui n'apparaît dans tous les spe.

    Pourtant, si vous désirez d'en avoir un rendrement différent comme demandé, c'est bien possible, bien entendu; mais pour le faire on est en effet demandé de faire un regroupement radicalement différent par rapport aux ci qui apparaîent dans tous les spe. Et maintenet, le regoupement est pour les ci mais avec la clé de id. Il faut faire attention de cela.

    Concrètement, on peut faire comme ça remplaçant la deuxième partie du template montré.
    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
            <xsl:for-each-group select="for $ci in //ci return $ci[some $spe in //spe satisfies count($spe/ci[. = $ci]) eq 0]" group-by="preceding-sibling::id/text()">
                <commun>
                    <xsl:for-each select="current-group()">
                        <xsl:if test="position()=1">
                            <id>
                                <xsl:value-of select="current-grouping-key()"/>
                            </id>
                        </xsl:if>
                        <ci>
                            <xsl:value-of select="." />
                        </ci>
                    </xsl:for-each>
                </commun>
            </xsl:for-each-group>
    Il peut y avoir d'amélioration si vous voulez, mais c'est ce que j'écrirerais rapidement et en premier temps.

  6. #6
    yos
    yos est déconnecté
    Membre confirmé
    Inscrit en
    Mai 2005
    Messages
    140
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 140
    Par défaut
    Merci tsuji pour ta réponse et ta disponibilité.
    Désolé je n'étais pas assez clair dans ma demande car l'idée est de faire un double groupement <ci><id> ou plus précisément de regrouper les liens <id><ci>, si par exemple l'<id> 1 est lié aux <ci> a et b et l'<id> 2 est lié aux <ci> a, b, d et f on obtient donc une fois le regroupement réalisé: les <id> 1 et 2 liés aux <ci> a et b et l'<id> 2 lié aux <ci> d et f.
    Merci pour votre aide.

  7. #7
    Membre Expert Avatar de tsuji
    Inscrit en
    Octobre 2011
    Messages
    1 558
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 1 558
    Par défaut
    A mon sens, l'issue ici n'est pas proprement un double groupement de ci et id. En fait, il est plus près d'un double regroupement sur l'ensemble puissant (de possible O(2**N) d'éléments distinctes). En tout cas, en toute généralité, c'est assez lourde en tant que processus. Mais, les combinaisons d'id possibles sont réalistiquement un tout petit sous-ensemble de l'ensemble complet et ça aide.

    Brèf, je peux proposer une attaque directe sans prétention tout vaine comme ci-desous. Je continue d'utiliser templates nommés quoique en principe xslt 2 puisse les épargner, mais j'ai trouvé de problème d'éfficacité si on fait itération sur une séquence de valeurs atomiques... C'est très compliqué d'expliquer le code, plutôt je trouverais trop fatiguant, hélas de le faire, même au niveau abstract, donc, il vous faut démembrer les templates utilsés en morceaux pour découvrer les intentions d'eux vous-même. Si ça devient une tache insurmontable en découvrant ses intentions, c'est que vous n'êtes pas tout à fait prêt et il vous faut rattrapper un peu à votre côté.
    Code xml : 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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    <xsl:variable name="num_spe" select="count(//spe)" />
    <xsl:variable name="doc" select="/" />
     
    <xsl:template match="/">
        <doc>
            <xsl:call-template name="process">
                <xsl:with-param name="mspec" select="$num_spe" />
            </xsl:call-template>
        </doc>
    </xsl:template>
     
    <xsl:template name="process">
        <xsl:param name="mspec" />
        <xsl:if test="$mspec &gt; 0">
            <xsl:if test="count(for $ci in //ci return $ci[count($doc//spe[ci = $ci]) = $mspec]) != 0">
                <xsl:variable name="interfrag">
                    <xsl:for-each-group select="for $ci in //ci return $ci[count($doc//spe[ci = $ci]) = $mspec]"
                        group-by="preceding-sibling::id">
                        <xsl:sort select="." />
                        <item>	
                            <xsl:for-each select="current-group()">
                                <xsl:if test="position()=1">
                                    <xsl:for-each select="current-grouping-key()">
                                        <id><xsl:value-of select="." /></id>
                                    </xsl:for-each>
                                </xsl:if>
                                <ci><xsl:value-of select="." /></ci>
                            </xsl:for-each>
                        </item>
                    </xsl:for-each-group>
                </xsl:variable>
     
                <xsl:for-each-group select="$interfrag/item" group-by="(self::item/ci[1])">
                    <commun>
                        <xsl:for-each select="current-group()">
                            <id><xsl:value-of select="id" /></id>
                        </xsl:for-each>
                        <xsl:for-each select="distinct-values(current-group()//ci)">
                            <ci><xsl:value-of select="." /></ci>
                        </xsl:for-each>
                    </commun>
                </xsl:for-each-group>
     
            </xsl:if>
     
            <xsl:call-template name="process">
                <xsl:with-param name="mspec" select="$mspec - 1" />
            </xsl:call-template>
     
        </xsl:if>
    </xsl:template>

  8. #8
    yos
    yos est déconnecté
    Membre confirmé
    Inscrit en
    Mai 2005
    Messages
    140
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 140
    Par défaut
    Super ! Merci beaucoup tsuji, ça à l'air de fonctionner
    C'est beaucoup plus clair en lisant la solution
    Encore merci.

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

Discussions similaires

  1. [PHP 5.3] Comment regrouper des elements d'un tableau par paire de 2
    Par Jarod51 dans le forum Langage
    Réponses: 2
    Dernier message: 23/04/2010, 12h02
  2. [dico]recherhce par element de la cle
    Par deeal dans le forum Général Python
    Réponses: 3
    Dernier message: 08/04/2005, 18h35
  3. Réponses: 5
    Dernier message: 29/09/2004, 12h05
  4. [DB2]Requête regroupement par intervals
    Par sm dans le forum DB2
    Réponses: 8
    Dernier message: 01/09/2004, 18h19
  5. Regroupement par mois
    Par fplanglois dans le forum SQL
    Réponses: 7
    Dernier message: 29/07/2003, 17h32

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