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 :

Regroupement d'une suite de frère sous le même père [XSLT 1.0]


Sujet :

XSL/XSLT/XPATH XML

  1. #1
    Membre à l'essai
    Femme Profil pro
    Inscrit en
    Février 2013
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations forums :
    Inscription : Février 2013
    Messages : 5
    Par défaut Regroupement d'une suite de frère sous le même père
    Bonjour,

    Je n'ai pas l'habitude de demander de l'aide sur des forums mais là j'ai fait toutes les recherches que je pouvais mais je n'ai pas trouvé de solution à mon problème...

    J'ai un fichier XML de la forme suivante :
    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
     
    <?xml version="1.0" encoding="UTF-8"?>
     
    <contenu>
          <tableau>
                <autres_balises>blabla</autres_balises>
          </tableau>
          <figure>
                <autres_balises2>blabla2</autres_balises2>
          </figure>
          <text>
                 <titre><autres_balises3>Letitre</autres_balises3></titre>
                 <sous_titre><autres_balises4>Lesoustitre</autres_balises4></sous_titre>
          </text>
          <pagination>blabla</pagination>
    </contenu>
    Et je voudrais obtenir quelque chose comme ça :
    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
     
     <sourceDoc>
          <surface>
                <table>
                       <other_tag1>blabla</other_tag>
                </table>
                <figure>
                       <other_tag2>blabla2</other_tag2>
                </figure>
          </surface>
          <text>
                 <title>
                       <other_tag3>Title</other_tag3>
                 </title>
                 <subtitle>
                       <other_tag4>Subtitle</other_tag4>
                 </subtitle>
          </text>
          <surface>
                <pagination>blabla</pagination>
          </surface>
    </sourceDoc>

    Donc pour expliquer ce que je voudrais faire : pour certains éléments définis je veut les regrouper sous <surface>, et d'autres sous <text>, tout en maintenant le traitement des autres enfants dans chacun des élements <tableau>, <figure>, <titre>, etc. J'ai mis ces éléments dans cet ordre là pour mon exemple (tableau puis figure, puis texte, etc), mais j'aurai d'autre fichiers xml avec des ordres différents (par exemple texte contenant titre, suivi de tableau, resuivi de texte, etc). Je dois de plus garder l'ordre dans lequel apparaissent ces différents éléments dans mon nouveau fichier xml.

    J'ai réfléchi la chose ainsi :
    En fonction du frère précédent et du noeud courant, ex : frère précédent = <figure> et frère courant = <texte>, on ferme la balise </surface> et on ouvre <text> par exemple. Mais ce traitement est compliqué (il faut traiter le cas de la toute première balise rencontrée, ainsi que la toute dernière avant <contenu>), et surtout l'erreur que j'obtiens est :" The element type "text" must be terminated by the matching end-tag "</text>"". Donc je ne peux à priori pas séparer la balise ouvrante de fermante. De toute façon je pense que cette manière de réfléchir ne correspond pas au mode de fonctionnement de xsl...
    Mais du coup je suis complètement bloquée... Est-ce que quelqu'un aurait des idées?

    Je suis désolée si je n'ai pas été claire, n'hésitez pas à me demander d'autres explications s'il le faut!

    Merci d'avance!

    Cécile

  2. #2
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 584
    Par défaut
    C'est... Assez compliqué en XSLT 1.0. Et sur ton exemple, les <text> ne sont pas spécialement regroupés. C'est plutôt des séparateurs entre les <surface> qui regroupent tout le reste.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 584
    Par défaut
    Ça devrait marcher avec une logique comme ça :

    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
    <xsl:template match="text">
      <xsl:copy-of select="."/>
    </xsl:template>
     
    <xsl:template match="*">
      <!-- Si c'est le premier d'une <surface>, générer la <surface>. Sinon ne rien faire -->
      <xsl:if test="not(preceding-sibling::*) or preceding-sibling::*[1][self::text]">
        <surface>
          <xsl:choose>
            <xsl:when test="not(following-sibling::text)">
              <xsl:apply-templates select=".|following-sibling::*" mode="boxed"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:variable name="nextText" select="generate-id(following-sibling::text)"/>
              <xsl:apply-templates select=".|following-sibling::*[generate-id(following-sibling::text) = $nextText]" mode="boxed"/>
            </xsl:otherwise>
          </xsl:choose>
        </surface>
      </xsl:if>
    </xsl:template>
     
    <xsl:template match="*" mode="boxed">
      <xsl:copy-of select="."/>
    </xsl:template>
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  4. #4
    Membre à l'essai
    Femme Profil pro
    Inscrit en
    Février 2013
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations forums :
    Inscription : Février 2013
    Messages : 5
    Par défaut
    Oui c'est vrai c'est plutôt sous <surface> qu'on a un regroupement...

    Mais, ce serait beaucoup plus simple en XSLT 2.0.? Je suis restée sur la version 1.0. parce que c'est celle que j'ai étudiée, mais s'il le faut vraiment, je peux passer à la 2.0...

  5. #5
    Membre à l'essai
    Femme Profil pro
    Inscrit en
    Février 2013
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations forums :
    Inscription : Février 2013
    Messages : 5
    Par défaut
    D'accord, je vais étudier ce que tu m'as proposé et je te tiens au courant!

    Merci beaucoup!

  6. #6
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 584
    Par défaut
    Citation Envoyé par cedeline Voir le message
    Mais, ce serait beaucoup plus simple en XSLT 2.0.?
    Oui. Ça reste un peu compliqué quand même, mais on arrive à exprimer ce qu'on veut directement :

    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
    <xsl:template match="contenu">
      <sourceDoc>
        <xsl:for-each-group select="*"
          group-starting-with="text | *[1] | *[preceding-sibling::*[1][self::text]]">
     
          <xsl:choose>
             <xsl:when test="current-group()[self::text]">
               <xsl:copy-of select="current-group()"/>
             </xsl:when>
             <xsl:otherwise>
               <surface>
                 <xsl:copy-of select="current-group()"/>
               </surface>
             </xsl:otherwise>
          </xsl:choose>
        </xsl:for-each-group>
      </sourceDoc>
    </xsl:template>
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  7. #7
    Membre à l'essai
    Femme Profil pro
    Inscrit en
    Février 2013
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations forums :
    Inscription : Février 2013
    Messages : 5
    Par défaut
    Alors, voilà ce que j'ai essayé (en XSLT 1.0.)

    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
     
    <xsl:template match="contenu">
    		<sourceDoc>
    		<xsl:choose>
    			<xsl:when test="(not(preceding-sibling::*) or preceding-sibling::*[1][self::texte]) and not(current()='texte')">
    				  <surface>
    				    <xsl:choose>
    					<xsl:when test="not(following-sibling::texte)">
    					  <xsl:apply-templates select=".|following-sibling::*" mode="boxed"/>
    					</xsl:when>
    					<xsl:otherwise>
    					  <xsl:variable name="nextText" select="generate-id(following-sibling::texte)"/>
    					  <xsl:apply-templates select=".|following-sibling::*[generate-id(following-sibling::texte) = $nextText]" mode="boxed"/>
    					</xsl:otherwise>
    				    </xsl:choose>
    				  </surface>
    			</xsl:when>
    			<xsl:otherwise>
    				<xsl:apply-templates select="texte"/>
    			</xsl:otherwise>
    		</xsl:choose>
    		</sourceDoc>
    	</xsl:template>
     
     
    	<xsl:template match='texte' >
    		<text>
    			<xsl:apply-templates/>
    		</text>
    	</xsl:template>
    et j'ai rajouté le mode="boxed" à chaque élément qui doit se trouver dans <surface>
    ex :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    	<xsl:template match='tableau' mode="boxed">
    		<table>
    			<xsl:apply-templates/>
    		</table>
    	</xsl:template>

    Donc ce que j'ai changé par rapport à ce que tu m'avais initialement donné:
    - j'ai remplacé "*" par "contenu" dans
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <xsl:template match="contenu">
    pour ne pas que ça s'applique au frère de <contenu>
    - j'ai aussi remplacé les "text" par "texte" car dans le xml à transformer c'est "texte"
    - j'ai transformé le "if" en "when" pour que lorsqu'on n'est pas dans un cas de <surface>, on applique le template de "texte"
    - et enfin, j'ai rajouté
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    and not(current()='texte')
    dans la condition du premier "when", pour traiter le cas où on a un <text> en tout premier frère (d'après ce que j'ai compris, la condition disait initialement que si l'élément actuel n'a pas de frère, alors c'est forcément une surface)

    Sauf que lorsque j’exécute ma feuille de style, je n'obtiens que les parties de texte <text>, il semble que ça ne rentre jamais dans la première condition, le premier when qui traite les éléments de <surface> ...

  8. #8
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 584
    Par défaut
    Citation Envoyé par cedeline Voir le message
    - j'ai remplacé "*" par "contenu" dans
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <xsl:template match="contenu">
    pour ne pas que ça s'applique au frère de <contenu>
    Sauf que le but de ce template, c'était clairement de s'appliquer à tout ce qui est sous <contenu> et qui n'est pas un <text>.
    Donc si tu voulais le remplacer, ça aurait dû être par match="contenu/*".
    Ou alors en gérant dans d'autres templates tout ce qui ne doit pas être géré dans celui-ci.

    Citation Envoyé par cedeline Voir le message
    - j'ai aussi remplacé les "text" par "texte" car dans le xml à transformer c'est "texte"
    Oui, moi je te donne la structure, mais il faut adapter à ton cas c'est sûr.

    Citation Envoyé par cedeline Voir le message
    - j'ai transformé le "if" en "when" pour que lorsqu'on n'est pas dans un cas de <surface>, on applique le template de "texte"
    C'est à ça que sert le template match="text". Le cas ne devrait jamais se présenter dans ce template-ci.

    Citation Envoyé par cedeline Voir le message
    - et enfin, j'ai rajouté
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    and not(current()='texte')
    dans la condition du premier "when", pour traiter le cas où on a un <text> en tout premier frère (d'après ce que j'ai compris, la condition disait initialement que si l'élément actuel n'a pas de frère, alors c'est forcément une surface)
    Alors déjà, current()='texte' ne fait absolument pas ce que tu crois. Tu aurais dû utiliser and not(self::texte) ou and name() != 'texte'.

    Mais comme je l'ai dit, le principe du template match="texte", c'est que du coup les <texte> ne viennent pas dans ce template-ci. Ce cas ne se présente donc jamais et cette condition est inutile.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  9. #9
    Membre à l'essai
    Femme Profil pro
    Inscrit en
    Février 2013
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations forums :
    Inscription : Février 2013
    Messages : 5
    Par défaut
    C'est bon ça marche!! Merci pour tes explications, j'avais pas bien compris le fonctionnement en effet.
    Les seules modifications que j'ai faites du coup sont de remplacer "*" par "contenu/*" comme tu me l'as précisé, et aussi pour 'texte' du coup j'ai mis 'contenu/texte', et là ça a marché!
    Voilà donc le code au final :

    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
     
     
    	<xsl:template match="contenu/*">
    	   <xsl:if test="not(preceding-sibling::*) or preceding-sibling::*[1][self::texte]">
    	    <surface>
    	      <xsl:choose>
    		<xsl:when test="not(following-sibling::texte)">
    		  <xsl:apply-templates select=".|following-sibling::*" mode="boxed"/>
    		</xsl:when>
    		<xsl:otherwise>
    		  <xsl:variable name="nextText" select="generate-id(following-sibling::texte)"/>
    		  <xsl:apply-templates select=".|following-sibling::*[generate-id(following-sibling::texte) = $nextText]" mode="boxed"/>
    		</xsl:otherwise>
    	      </xsl:choose>
    	    </surface>
    	  </xsl:if>
    	</xsl:template>
     
    	<xsl:template match='contenu/texte'>
    		<text>
    			<xsl:apply-templates/>
    		</text>
    	</xsl:template>
    Merci infiniment pour ton aide thelvin!

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 31/10/2006, 16h47
  2. Réponses: 2
    Dernier message: 07/02/2006, 19h44
  3. execution d'une macro d'access sous delphi
    Par galendor_d'ambre dans le forum Bases de données
    Réponses: 6
    Dernier message: 10/02/2004, 15h58
  4. [dbase3]Convertir une base de données sous windows
    Par nux dans le forum Autres SGBD
    Réponses: 2
    Dernier message: 04/10/2003, 14h25
  5. Une base de données sous windows ???
    Par nux dans le forum Décisions SGBD
    Réponses: 10
    Dernier message: 23/09/2003, 16h04

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