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 :

Compacter plusieurs noeuds [XSLT 1.0]


Sujet :

XSL/XSLT/XPATH XML

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre habitué
    Homme Profil pro
    Responsable de projet fonctionnel
    Inscrit en
    Septembre 2015
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Responsable de projet fonctionnel

    Informations forums :
    Inscription : Septembre 2015
    Messages : 11
    Par défaut Compacter plusieurs noeuds
    Bonjour,

    J'ai un fichier xml avec cette syntaxe:
    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
    23
    24
    25
    <Occurrence id="id1" occurrenceRefs="id2 id3 id4 id5">
    	<UserValue value="" title="Quantity"></UserValue>
    	<UserValue value="" title="SequenceNumber"></UserValue>
    	<UserValue value="ID-01" title="Item_ID"></UserValue>
    </Occurrence>
    <Occurrence id="id2" parentRef="#id1">
    	<UserValue value="1" title="Quantity"></UserValue>
    	<UserValue value="10" title="SequenceNumber"></UserValue>
    	<UserValue value="ID-02" title="Item_ID"></UserValue>
    </Occurrence>
    <Occurrence id="id3" parentRef="#id1">
    	<UserValue value="1" title="Quantity"></UserValue>
    	<UserValue value="10" title="SequenceNumber"></UserValue>
    	<UserValue value="ID-02" title="Item_ID"></UserValue>
    </Occurrence>
    <Occurrence id="id4" parentRef="#id1">
    	<UserValue value="1" title="Quantity"></UserValue>
    	<UserValue value="20" title="SequenceNumber"></UserValue>
    	<UserValue value="ID-03" title="Item_ID"></UserValue>
    </Occurrence>
    <Occurrence id="id5" parentRef="#id1">
    	<UserValue value="1" title="Quantity"></UserValue>
    	<UserValue value="20" title="SequenceNumber"></UserValue>
    	<UserValue value="ID-03" title="Item_ID"></UserValue>
    </Occurrence>
    Pour l'instant je génére ce tableau:
    Sequence Number Quantity Item ID
    X ID-01
    10 1 ID-02
    10 1 ID-02
    20 1 ID-03
    20 1 ID-03

    Mon but est de générer un fichier html comprenant le tableau ci-dessous:
    Sequence Number Quantity Item ID
    X ID-01
    10 2 ID-02
    20 2 ID-03


    Pour générer ce tableau, j'utilise une fonction récursive (en utilisant string-before et string-after sur "occurrenceRefs"), et pour l'instant je ne trouve pas comment compacter mes différents noeuds qui :
    - sont lié au même niveau de l'arbre (le xml représente un arbre/nomenclature);
    - ont un "SequenceNumber" identique;
    - ont un "Item_ID" identique.

    Pour l'instant mon idée est de trouver un moyen de conserver l'id du noeud traité précédemment, mais je bute un peu sur comment remonter sur la ligne supérieure dans le html pour additionner les quantités.


    Merci d'avance 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
    Oui, c'est un problème typique dit groupement ... On peut le faire d'un façon plus avancée et efficace pour un tableau important en utilisant l'élément xsl:key, et ce n'est pas difficile à trouver des examples en googlant avec ce mot clé. Je peux d'ailleurs vous proposer une façon plus élémentaire sans xsl:key. C'est élémentaire mais plus instructif et je trouve aussi pour cela plus intéressant.
    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
    <xsl:template match="Occurrence">
        <xsl:variable name="filter" select="UserValue[@title='Item_ID']/@value" />
        <xsl:choose>
            <xsl:when test="not(preceding-sibling::Occurrence[UserValue[@title='Item_ID']/@value=$filter])">
                <tr>
                    <td><xsl:value-of select="concat('&#xa0;', UserValue[@title='SequenceNumber']/@value)" /></td>
                    <td>
                        <xsl:value-of select="sum(
                            self::Occurrence/UserValue[@title='Quantity']/@value
                            |
                            following-sibling::Occurrence[UserValue[@title='Item_ID']/@value=$filter]/UserValue[@title='Quantity']/@value
                            )"
                        />
                    </td>
                    <td><xsl:value-of select="concat('&#xa0;', UserValue[@title='Item_ID']/@value)" /></td>
                </tr>
            </xsl:when>
            <xsl:otherwise>
                <!-- ne rien faire -->
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    En gros, c'est ça.

  3. #3
    Membre habitué
    Homme Profil pro
    Responsable de projet fonctionnel
    Inscrit en
    Septembre 2015
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Responsable de projet fonctionnel

    Informations forums :
    Inscription : Septembre 2015
    Messages : 11
    Par défaut
    Merci tsuji pour votre aide, je suis en train de tester la méthode élémentaire.

    Par contre j'ai un doute sur le fait de faire le test sur les noeuds précédents avec 2 conditions: même ID et même SequenceNumber.

    Pensez-vous que cela soit possible? Car je ne vois pas comment l'écrire (et Google n'est pas mon ami sur ce coup).

    J'ai commencé par écrire cela, mais je suis convaincu que cela ne fonctionne pas (les 2 conditions se vérifient indépendamment je pense)

    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
    23
    24
    25
    <xsl:template match="Occurrence">
        <xsl:variable name="filterId" select="/plm:PLMXML/plm:ProductView/plm:Occurrence/plm:UserValue[@title='Item_ID']/@value"/>
        <xsl:variable name="filterSeqno" select="/plm:PLMXML/plm:ProductView/plm:Occurrence/plm:UserValue[@title='SequenceNumber']/@value"/>
        <xsl:variable name="occ" select="/plm:PLMXML/plm:ProductView/plm:Occurrence"/>
     
        <xsl:choose>
            <xsl:when test="not(preceding-sibling::$occ[UserValue[@title='Item_ID']/@value=$filterId]) and not(preceding-sibling::$occ[UserValue[@title='SequenceNumber']/@value=$filterFindno])">
                <tr>
                    <td><xsl:value-of select="concat('&#xa0;', UserValue[@title='SequenceNumber']/@value)" /></td>
                    <td>
                        <xsl:value-of select="sum(
                            self::Occurrence/UserValue[@title='Quantity']/@value
                            |
                            following-sibling::Occurrence[UserValue[@title='Item_ID']/@value=$filter]/UserValue[@title='Quantity']/@value
                            )"
                        />
                    </td>
                    <td><xsl:value-of select="concat('&#xa0;', UserValue[@title='Item_ID']/@value)" /></td>
                </tr>
            </xsl:when>
            <xsl:otherwise>
                <!-- ne rien faire -->
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    En tout cas, encore merci pour ta réponse, elle m'a vraiment fait avancée

  4. #4
    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
    C'est vrai j'ai pensé que la valeur de SequenceNumber soit forcément le même pour une valeur d'Item_ID donnée. Si ça peux varier indépendemment, il faut tenir compte de ce fait. Les variables comme vous entendez seraient quelque chose comme ça.
    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    <xsl:variable name="filterId" select="UserValue[@title='Item_ID']/@value" />
    <xsl:variable name="filterSeqno" select="UserValue[@title='SequenceNumber']/@value" />
    Les variables $filterId et $filterSeqno sont celles déterminées par l'Occurrence en contexte, pas n'importe quel Occurrence déterminé par un xpath absolu à partir de la racine /plmLMXML ou je ne sais quoi. C'est important.

    Et puis le conditionnel serait comme ceci.
    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    <xsl:when test="not(preceding-sibling::Occurrence[
        UserValue[@title='Item_ID']/@value=$filterId
        and
        UserValue[@title='SequenceNumber']/@value=$filterSeqno
    ])">

    Tous xpaths sont relatifs au contexte Occurrence, donc, les xpaths absolus ne me semblent pas pertinents. Si l'Occurrence se voit partout, au plus, on met preceding:: et following:: au lieu de preceding-siblings:: et following-siblings::. Mais je n'ai pas encore regardé votre script de très près.

    ps: Pour faire une somme numérique sur la valeur de @title='Quantity', il faut que @value soit numérique. Un texte vide n'est parfois par assez bon pour certaine implémentation. L'admissibilité par casting un texte vide à un zero est implémentation-dépendant. Je n'avait pas mentionné ça avant ! Donc, pour faire tester, il vaut mieux de mettre en garde de ça et remplacer les texte vides par "0" pour une meilleure assurance.

  5. #5
    Membre habitué
    Homme Profil pro
    Responsable de projet fonctionnel
    Inscrit en
    Septembre 2015
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Responsable de projet fonctionnel

    Informations forums :
    Inscription : Septembre 2015
    Messages : 11
    Par défaut
    Merci !

    Pour le xpath absolu, il ne l'est pas vraiment, j'ai oublié la référence de l'occurrence (id), c'est grâce à cet id que je récupère via "occurrenceRefs" chaque occurrence que je parcours 1 à 1.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    <xsl:variable name="filterId" select="/plm:PLMXML/plm:ProductView/plm:Occurrence[@id=$occid]/plm:UserValue[@title='Item_ID']/@value"/>
    <xsl:variable name="filterSeqno" select="/plm:PLMXML/plm:ProductView/plm:Occurrence[@id=$occid]/plm:UserValue[@title='SequenceNumber']/@value"/>

    Voici mon code xsl (en court car il fait 1300 lignes environ) :

    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
    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
    52
    <xsl:variable name="primaryOccRef" select="/plm:PLMXML/plm:ProductView/@primaryOccurrenceRef"/>
     
    <xsl:call-template name="createCL">
    	<xsl:with-param name="occStr" select="/plm:PLMXML/plm:ProductView/plm:Occurrence[@id=$primaryOccRef]/@occurrenceRefs"/>
    </xsl:call-template>
     
    <xsl:template name="createCL">
    	<xsl:param name="occStr"/>
     
    	<xsl:if test="$occStr!=''">
    		<xsl:choose>
    			<xsl:when test="contains($occStr,' ')">
    				<xsl:variable name="occid" select="substring-before($occStr,' ')"/>
     
    				<xsl:call-template name="createCL">
    					<xsl:with-param name="occStr" select="$occid"/>
    				</xsl:call-template>
     
    				<xsl:call-template name="createCL">
    					<xsl:with-param name="occStr" select="substring-after($occStr,' ')"/>
    				</xsl:call-template>
    			</xsl:when>
     
    			<xsl:otherwise>
    				<xsl:call-template name="creCLext">
    					<xsl:with-param name="occid" select="$occStr"/>
    				</xsl:call-template>
    			</xsl:otherwise>
    		</xsl:choose>
    	</xsl:if>
    </xsl:template>
     
    <xsl:template name="creCLext">
        <xsl:param name="occid"/>
     
        <xsl:variable name="quantity" select="/plm:PLMXML/plm:ProductView/plm:Occurrence[@id=$occid]/plm:UserValue[@title='Quantity']/@value" />
        <xsl:variable name="findno" select="/plm:PLMXML/plm:ProductView/plm:Occurrence[@id=$occid]/plm:UserValue[@title='SequenceNumber']/@value" />
        <xsl:variable name="itemref" select="/plm:PLMXML/plm:ProductView/plm:Occurrence[@id=$occid]/plm:UserValue[@title='instanceRef']/@value" />
        <xsl:variable name="itemid" select="/plm:PLMXML/plm:ItemRevision[@id=$itemref]/plm:UserValue[@title='Item_ID']/@value" />
     
        <tr>
    	<td>
    		<xsl:value-of select="substring($findno,1,4)"/>
    	</td>
    	<td>
    		<xsl:value-of select="$quantity"/>
    	</td>
    	<td>
    		<xsl:value-of select="$itemid"/>
    	</td>
        </tr>
    </template>
    Et un exemple du xml d'entrée (aussi en plus court, ils font au minimum 3000 lignes):
    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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    <PLMXML>
    <ProductView id="id4" ruleRefs="#id2" rootRefs="id1" primaryOccurrenceRef="id1">
    	<Occurrence id="id1" instanceRef="#id10" occurrenceRefs="id2 id3 id4 id5">
    		<UserValue value="" title="Quantity"></UserValue>
    		<UserValue value="" title="SequenceNumber"></UserValue>
    	</Occurrence>
    	<Occurrence id="id2" instanceRef="#id11" parentRef="#id1">
    		<UserValue value="1" title="Quantity"></UserValue>
    		<UserValue value="10" title="SequenceNumber"></UserValue>
    	</Occurrence>
    	<Occurrence id="id3" instanceRef="#id11" parentRef="#id1">
    		<UserValue value="1" title="Quantity"></UserValue>
    		<UserValue value="10" title="SequenceNumber"></UserValue>
    	</Occurrence>
    	<Occurrence id="id4" instanceRef="#id12" parentRef="#id1">
    		<UserValue value="1" title="Quantity"></UserValue>
    		<UserValue value="20" title="SequenceNumber"></UserValue>
    	</Occurrence>
    	<Occurrence id="id5" instanceRef="#id12" parentRef="#id1">
    		<UserValue value="1" title="Quantity"></UserValue>
    		<UserValue value="20" title="SequenceNumber"></UserValue>
    	</Occurrence>
    </ProductView>
    <ItemRevision id="id10">
    	<UserValue value="ID-01" title="Item_ID"/>
    </ItemRevision>
    <ItemRevision id="id11">
    	<UserValue value="ID-02" title="Item_ID"/>
    </ItemRevision>
    <ItemRevision id="id12">
    	<UserValue value="ID-03" title="Item_ID"/>
    </ItemRevision>
    </PLMXML>
    Malheureusement cela ne fonctionne pas et j'ai bien peur de devoir passer par un xsl:key, non?

  6. #6
    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
    Si on change la sturcture tous les deux réponses, on n'en finirait pas. En tout cas, si vous entendez qu'il y a beaucoup de PLMXML et qu'on est dans le contexte de PLMXML, les xpath absolus ne seraient toujours pas corrects. Enfin, je ne sais même pas quel contexte on se place, donc, je n'ai en principe rien à dire pour ne pas jéter plus de confusion. Avec les nouvelles donnée, je ne sais même pas si c'est prêt à faire un groupement dans l'étape présent de xslt.

    En tout cas, je vois ceci est faux, tout simplement.
    <xsl:variable name="itemref" select="/plm:PLMXML/plm:ProductView/plm:Occurrence[@id=$occid]/plm:UserValue[@title='instanceRef']/@value" />
    (où se situe @title='instanceRef' !?) et donc,
    <xsl:variable name="itemid" select="/plm:PLMXML/plm:ItemRevision[@id=$itemref]/plm:UserValue[@title='Item_ID']/@value" />
    n'est non plusaussi.

    Si vous voulez faire un scale-down modèle de xml et xslt, il faut toujours préserver tous les aspects essentiels : le xml les namespaces, le xslt le contexte (le template, le match). Si non, je répète, on n'en finit pas jamais.

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

Discussions similaires

  1. [XSLT] for-each imbriqué et plusieurs noeuds
    Par Trunks dans le forum XSL/XSLT/XPATH
    Réponses: 3
    Dernier message: 31/10/2008, 15h08
  2. [XPATH] Débutant: Sélectionner un ou plusieurs noeuds
    Par Invité dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 07/12/2007, 10h30
  3. [DOM] suppression de plusieurs noeuds
    Par yannux dans le forum Bibliothèques et frameworks
    Réponses: 5
    Dernier message: 09/08/2007, 11h02
  4. [XML DOM]Supprimer plusieurs noeud
    Par Shandler dans le forum APIs
    Réponses: 9
    Dernier message: 06/06/2007, 19h30
  5. [XSLT] Plusieurs noeuds fils en 1 tour de boucle
    Par Korko Fain dans le forum XSL/XSLT/XPATH
    Réponses: 3
    Dernier message: 29/05/2007, 14h30

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