Valid XHTML     Valid CSS2    

Développement Web et représentation de données :

Technologie XML, DTD, XSD et XSL ;

applications à la bureautique et à la bioinformatique

Exercices corrigés, série 3 : sélections XPATH et transformations XSL

                     gilles.hunault "at" univ-angers.fr

 

Table des matières cliquable

  1. Expressions XPATH élémentaires (films)

  2. Expressions XPATH avancées (films)

  3. Expressions XPATH élémentaires (bioinformatique)

  4. Expressions XPATH avancées (bioinformatique)

  5. Compréhension de la transformation vide

  6. Comptages avec XSL (1)

  7. Transformations entre éléments et attributs

  8. Ajouts et modifications d'éléments ou d'attributs

  9. Comptages avec XSL (2)

10. Suppression de la mise en forme XHTML

11. Tris avec XSL

12. Fichiers inclus, sous-programmes et variables en XSL

13. Une transformation à peine plus complexe

14. Questions diverses

 

Il est possible d'afficher toutes les solutions via ?solutions=1.

 

1. Expressions XPATH élémentaires (films)

Pour ce premier exercice, on utilisera le fichier films2.xml qui est une version légèrement modifiée du fichier de P. Rigaux à qui nous avons emprunté certains exercices.

Quelle est la différence entre xmlstarlet el et xmlstarlet el -u ?

Quelle est la différence entre /* et //* ? Utilisez xmllint en mode "shell" pour le montrer.

Donner le titre de tous les films puis le nom de tous les artistes (metteurs en scène et acteurs).

Que signifie /FILMSETARTISTES/FILMS/FILM[@Annee=1990]/TITRE ? Trouvez une expression XPATH plus concise qui fournit le même résultat.

Donnez les titres des films avec Bruce Willis.

Dans Reservoir dogs, quel personnage (élément INTITULE) joue Harvey Keitel ?

Quel metteur en scène correspond à la référence 3 ?

Solution :  

En mode el, xmlstarlet affiche le chemin absolu de tous les éléments. Avec l'option -u, chaque élément est affiché de façon unique :


     xmlstarlet el films2.xml |  wc -l
     1248
     
     xmlstarlet el -u films2.xml |  wc -l
     18
     
     xmlstarlet el films2.xml
     
     FILMSETARTISTES
     FILMSETARTISTES/FILMS
     FILMSETARTISTES/FILMS/FILM
     FILMSETARTISTES/FILMS/FILM/TITRE
     FILMSETARTISTES/FILMS/FILM/GENRE
     FILMSETARTISTES/FILMS/FILM/PAYS
     FILMSETARTISTES/FILMS/FILM/MES
     FILMSETARTISTES/FILMS/FILM/ROLES
     FILMSETARTISTES/FILMS/FILM/ROLES/ROLE
     FILMSETARTISTES/FILMS/FILM/ROLES/ROLE/PRENOM
     FILMSETARTISTES/FILMS/FILM/ROLES/ROLE/NOM
     FILMSETARTISTES/FILMS/FILM/ROLES/ROLE/INTITULE
     FILMSETARTISTES/FILMS/FILM/ROLES/ROLE
     FILMSETARTISTES/FILMS/FILM/ROLES/ROLE/PRENOM
     FILMSETARTISTES/FILMS/FILM/ROLES/ROLE/NOM
     FILMSETARTISTES/FILMS/FILM/ROLES/ROLE/INTITULE
     FILMSETARTISTES/FILMS/FILM/RESUME
     FILMSETARTISTES/FILMS/FILM
     FILMSETARTISTES/FILMS/FILM/TITRE
     FILMSETARTISTES/FILMS/FILM/GENRE
     FILMSETARTISTES/FILMS/FILM/PAYS
     FILMSETARTISTES/FILMS/FILM/MES
     FILMSETARTISTES/FILMS/FILM/ROLES
     FILMSETARTISTES/FILMS/FILM/ROLES/ROLE
     FILMSETARTISTES/FILMS/FILM/ROLES/ROLE/PRENOM
     FILMSETARTISTES/FILMS/FILM/ROLES/ROLE/NOM
     FILMSETARTISTES/FILMS/FILM/ROLES/ROLE/INTITULE
     FILMSETARTISTES/FILMS/FILM/RESUME
     FILMSETARTISTES/FILMS/FILM
     FILMSETARTISTES/FILMS/FILM/TITRE
     ...
     FILMSETARTISTES/ARTISTES/ARTISTE/ANNEENAISS
     FILMSETARTISTES/ARTISTES/ARTISTE
     FILMSETARTISTES/ARTISTES/ARTISTE/ARTNOM
     FILMSETARTISTES/ARTISTES/ARTISTE/ARTPRENOM
     FILMSETARTISTES/ARTISTES/ARTISTE/ANNEENAISS
     FILMSETARTISTES/ARTISTES/ARTISTE
     FILMSETARTISTES/ARTISTES/ARTISTE/ARTNOM
     FILMSETARTISTES/ARTISTES/ARTISTE/ARTPRENOM
     FILMSETARTISTES/ARTISTES/ARTISTE/ANNEENAISS
     
     xmlstarlet el -u films2.xml
     
     FILMSETARTISTES
     FILMSETARTISTES/ARTISTES
     FILMSETARTISTES/ARTISTES/ARTISTE
     FILMSETARTISTES/ARTISTES/ARTISTE/ARTNOM
     FILMSETARTISTES/ARTISTES/ARTISTE/ARTPRENOM
     FILMSETARTISTES/ARTISTES/ARTISTE/ANNEENAISS
     FILMSETARTISTES/FILMS
     FILMSETARTISTES/FILMS/FILM
     FILMSETARTISTES/FILMS/FILM/GENRE
     FILMSETARTISTES/FILMS/FILM/MES
     FILMSETARTISTES/FILMS/FILM/PAYS
     FILMSETARTISTES/FILMS/FILM/RESUME
     FILMSETARTISTES/FILMS/FILM/ROLES
     FILMSETARTISTES/FILMS/FILM/ROLES/ROLE
     FILMSETARTISTES/FILMS/FILM/ROLES/ROLE/INTITULE
     FILMSETARTISTES/FILMS/FILM/ROLES/ROLE/NOM
     FILMSETARTISTES/FILMS/FILM/ROLES/ROLE/PRENOM
     FILMSETARTISTES/FILMS/FILM/TITRE
     
     

La notation AFP /* affiche les éléments directement sous la racine alors que //* affiche tous les éléments :


     xmllint --shell films2.xml
     / > ls /*
     ta-        1
     ---       97 FILMS
     ta-        1
     ---      235 ARTISTES
     ta-        1
     / > ls //*
     ta-        1
     ---       97 FILMS
     ta-        1
     ---      235 ARTISTES
     ta-        1
     ta-        1
     -a-       11 FILM
     ta-        1
     -a-       11 FILM
     ta-        1
     -a-       11 FILM
     ta-        1
     -a-        9 FILM
     ta-        1
     -a-       11 FILM
     ta-        1
     -a-       11 FILM
     ta-        1
     -a-       11 FILM
     ta-        1
     -a-       11 FILM
     ta-        1
     -a-       11 FILM
     ta-        1
     -a-       11 FILM
     ta-        1
     -a-       11 FILM
     ta-        1
     ...
     ta-        1
     ---        1 TITRE
     ta-        1
     ---        1 GENRE
     ---        1 PAYS
     -a-        0 MES
     ta-        1
     ---        3 ROLES
     ta-        1
     ---        1 RESUME
     ta-        1
     ta-        7 Vertigo
     ta-        5 Drame
     ta-        3 USA
     -a-        0 MES
     ta-        1
     ---        4 ROLE
     ---        4 ROLE
     ...
     

On trouvera dans xmllint_long.txt l'affichage complet (2732 lignes !) de la sortie de //*.

Un titre de film correspond est le contenu texte d'un élément TITRE dont la localisation absolue est /FILMSETARTISTES/FILMS/FILM/TITRE mais on peut raccourcir en //TITRE car TITRE n'est pas utilisé ailleurs. De même, un nom d'artiste est /FILMSETARTISTES/ARTISTES/ARTISTE/ARTNOM qu'on peut raccourcir en //ARTNOM.

L'expression /FILMSETARTISTES/FILMS/FILM[@Annee=1990]/TITRE filtre les films et ne retient que ceux qui vérifient @Annee=1990, c'est-à-dire qu'elle ne garde que les éléments FILM dont l'attribut Annee vaut 1990. Une fois sélectionnés, on affiche le titre de ces éléments. On peut donc utiliser plus simplement //FILM[@Annee=1990]/TITRE.


     xmllint --shell films2.xml
     
     / > ls //TITRE
     ta-        7 Vertigo
     ta-        5 Alien
     ta-        7 Titanic
     tan        9 Sacrifice
     tan       10 Volte/Face
     [...]
     t-n       23 Le cinqui#C3#A8me #C3#A9l#C3#A9ment
     t--        5 L#C3#A9on
     ta-        6 Nikita
     tan       13 Le grand bleu
     / > ls //FILM[@Annee=1990]/TITRE
     t--       21 58 minutes pour vivre
     ta-        8 Van Gogh
     t--       22 Le silence des agneaux
     ta-        6 Nikita
     / >
     

NOM et PRENOM sont des sous-éléments de ROLE, lui-même sous-élément de /FILMSETARTISTES/FILMS/FILM/ROLES. Comme Bruce est la valeur de l'élément PRENOM recherché et Willis celui de NOM, le filtre est : [ROLES/ROLE/PRENOM="Bruce" and ROLES/ROLE/NOM="Willis"] et, pour obtenir le titre des films, on entoure ceci de FILM et TITRE, soit la solution /FILMSETARTISTES/FILMS/FILM[ROLES/ROLE/PRENOM="Bruce" and ROLES/ROLE/NOM="Willis"]/TITRE. Avec des chemins relatifs, on peut se contenter de //FILM et de .//PRENOM :


     xmllint --shell films2.xml
     
     / > ls /FILMSETARTISTES/FILMS/FILM[ROLES/ROLE/PRENOM="Bruce" and ROLES/ROLE/NOM="Willis"]/TITRE
     
     t--       17 Pi#C3#A8ge de cristal
     t--       21 58 minutes pour vivre
     t--       25 L'arm#C3#A9e des douze singes
     tan       12 Pulp fiction
     t-n       23 Le cinqui#C3#A8me #C3#A9l#C3#A9ment
     
     / > ls //FILM[.//PRENOM="Bruce" and .//NOM="Willis"]/TITRE
     
     t--       17 Pi#C3#A8ge de cristal
     t--       21 58 minutes pour vivre
     t--       25 L'arm#C3#A9e des douze singes
     tan       12 Pulp fiction
     t-n       23 Le cinqui#C3#A8me #C3#A9l#C3#A9ment
     
     
     
     

NOM, PRENOM et INTITULE sont des sous-éléments de ROLE alors que TITRE est un sous-élément de FILM. Il faut donc utiliser conjointement les deux filtres TITRE='Reservoir dogs' et PRENOM='Harvey' and NOM='Keitel'. Comme TITRE est plus haut que ROLE dans la hiérarchie, il faut commencer par filtrer sur TITRE :


     xmllint --shell films2.xml
     
     / > ls //FILM[TITRE='Reservoir dogs']/ROLES/ROLE[PRENOM="Harvey" and NOM="Keitel"]/INTITULE
     tan       15 Mr. White/Larry
     

Pour le metteur en scène, la solution est //ARTISTE[@id=3]/ARTNOM, volontairement non expliquée.

 

2. Expressions XPATH avancées (films)

On utilise toujours films2.xml et xmllint en mode shell pour cet exercice. Donner la liste de toutes les références aux metteurs en scène puis donner la liste des noms des metteurs en scène référencés.

Peut-on facilement afficher le nom et les prénoms des metteurs en scène ? De façon lisible ? Enfin, donner la liste des noms des metteurs en scène distincts triée par ordre alphabétique.

Solution :  

Les références de metteurs en scène sont les attributs idref des éléments MEF, donc //MES/@idref suffit pour obtenir toutes les références demandées. Les noms des metteurs en scène sont les sous-éléments ARTNOM de ARTISTE qu'il faut filtrer, donc on ne peut pas utiliser seulement //ARTISTE/ARTNOM. Le filtre doit faire correspondre l'attribut id de ARTISTE avec un attribut idref quelconque de MES, soit : //ARTISTE[@id=//MES/@idref]/ARTNOM. Ecrire //ARTISTE[./@id=//MES/@idref]/ARTNOM donc avec un point devant @id est peut-être plus intéressant (mais plus long à écrire) pour rappeler qu'il s'agit de l'attribut de l'élément courant du filtre.


     xmllint --shell films2.xml
     
     / > ls //MES/@idref
     ta-        1 3
     ta-        1 4
     ta-        1 6
     ta-        1 9
     ta-        2 10
     ta-        2 13
     ta-        2 17
     ta-        2 20
     ta-        1 4
     ta-        1 4
     ta-        2 26
     ta-        2 28
     ta-        2 29
     ta-        2 31
     ta-        2 33
     ta-        2 34
     ta-        2 37
     ta-        2 41
     ta-        1 6
     ta-        2 45
     ta-        2 49
     ta-        2 52
     ta-        2 58
     ta-        2 61
     ta-        2 64
     ta-        2 68
     ta-        2 20
     ta-        2 71
     ta-        2 74
     ta-        2 45
     ta-        2 79
     ta-        2 81
     ta-        2 83
     ta-        2 87
     ta-        1 3
     ta-        2 91
     ta-        1 3
     ta-        2 37
     ta-        3 101
     ta-        3 101
     ta-        1 3
     ta-        1 3
     ta-        1 3
     ta-        3 111
     ta-        3 111
     ta-        3 111
     ta-        3 111
     ta-        3 111
     / > ls //ARTISTE[@id=//MES/@idref]/ARTNOM
     ta-        7 Cameron
     tan        9 Hitchcock
     ta-        5 Scott
     tan        9 Tarkovski
     ta-        3 Woo
     ta-        6 Burton
     ta-        6 Mendes
     ta-        8 Eastwood
     tan        9 McTierman
     ta-        6 Harlin
     ta-        6 Pialat
     ta-        7 Fincher
     ta-        7 Gilliam
     ta-        6 Annaud
     tan        9 Tarantino
     ta-        8 Farrelly
     tan        9 Spielberg
     ta-        5 Demme
     ta-        7 Chapman
     ta-        8 Emmerich
     tan        9 Wachowski
     ta-        8 De Palma
     ta-        8 Kurozawa
     ta-        7 Girault
     ta-        5 Palud
     ta-        8 Levinson
     ta-        5 Scott
     ta-        7 Leconte
     ta-        7 Pernnou
     ta-        8 Marquand
     ta-        7 Kubrick
     ta-        6 Besson
     

Dans la mesure où PRENOM et NOM sont les deux premiers sous-éléments de ROLE, on peut filtrer avec position() pour avoir les noms et prénoms, mais pas de façon lisible si on n'utilise que XPATH. Le tri non plus ne peut pas se faire avec un simple ls. Une transformation XSL pour répondre à ces questions sera fournie à l'exercice 9.


     xmllint --shell films2.xml
     
     / >      ls //ARTISTE[@id=//MES/@idref]/*[position()<3]
     
     ta-        7 Cameron
     ta-        5 James
     tan        9 Hitchcock
     ta-        6 Alfred
     ta-        5 Scott
     ta-        6 Ridley
     tan        9 Tarkovski
     ta-        6 Andrei
     ta-        3 Woo
     ta-        4 John
     ta-        6 Burton
     ta-        3 Tim
     ta-        6 Mendes
     ta-        3 Sam
     ta-        8 Eastwood
     ta-        5 Clint
     tan        9 McTierman
     ta-        4 John
     ta-        6 Harlin
     ta-        5 Renny
     ta-        6 Pialat
     ta-        7 Maurice
     ta-        7 Fincher
     ta-        5 David
     ...
     

 

3. Expressions XPATH élémentaires (bioinformatique)

Pour cet exercice, on utilise les fichiers 424143.gbx.xml (NCBI) et P14602.xml (UNIPROT) qui correspondent à la protéine AAA18335 vue à la série d'exercices numéro 1.

Sachant qu'au NCBI les identifiants sont les contenus texte des éléments GBSeqid, lister tous les identifiants liés à la protéine. Comment n'afficher que l'identifiant GenInfo, c'est-à-dire celui qui commence par gi| ? On utilisera astucieusement xmlstarlet puis xmllint pour trouver les identifiants avant d'écrire une expression XPATH qui affiche les identifiants complets puis une transformation XSL qui n'affiche que la valeur du gi, soit ici bien sûr 424143.

Solution :  

Après avoir lu les sorties de la commande xmlstarlet el -u AAA18335.xml, on exécute la commande xmlstarlet el -u AAA18335.xml | grep GBSeqid qui montre que l'élément GBSeqid apparait une seule fois dans la liste des éléments. Donc au lieu de /GBSet/GBSeq/GBSeq_other-seqids/GBSeqid on peut se contenter de //GBSeqid pour accéder aux identifiants. Il existe une fonction starts-with en XSL donc pour obtenir seulement le gi on doit filtrer par //GBSeqid[starts-with(.,'gi|')] ou par //GBSeqid[starts-with(text(),'gi|')]. On peut facilement vérifier ces expressions XPATH avec xmllint en mode "shell" :


     > cp 424143.gbx.xml AAA18335.xml
     
     > xmlstarlet el -u AAA18335.xml | grep GBSeqid
     
     GBSet/GBSeq/GBSeq_other-seqids/GBSeqid
     
     > xmllint --shell AAA18335.xml
     
     / > ls //GBSeqid
     tan       14 gb|AAA18335.1|
     tan        9 gi|424143
     / > ls //GBSeqid[starts-with(.,'gi|')]
     tan        9 gi|424143
     / > ls //GBSeqid[starts-with(text(),'gi|')]
     tan        9 gi|424143
     / > bye
     
     

La première transformation XSL, pour obtenir les identifiants complets, est ultra-classique : à partir de la racine, on sélectionne les //GBSeqid comme règle de sélection et dans la gestion de ces éléments, on affiche . ou text(), ce qui est la même chose ici. Enfin, on utilise xsl:text pour générer un saut de ligne soit la transformation ncbi_gi_1.xsl. Pour la seconde transformation XSL, où on veut juste le numéro d'identifiant, on utilise //GBSeqid[starts-with(text(),'gi|')] comme filtre et pour afficher on profite de substring-after, soit la transformation ncbi_gi_2.xsl.

Voici les deux transformations :

ncbi_gi_1.xsl       ncbi_gi_2.xsl       

Et leurs résultats :


     > exsl AAA18335.xml ncbi_gi_1.xsl
     
     gb|AAA18335.1|
     gi|424143
     
     > exsl AAA18335.xml ncbi_gi_2.xsl
     424143
     

Remarque : on aurait pu utiliser xsltproc ncbi_gi_1.xsl AAA18335.xml et xsltproc ncbi_gi_2.xsl AAA18335.xml pour exécuter les transformations XSL.

Un simple grep de gi ou de info sur le fichier P14602.xml montre qu'il n'y a pas d'informations liées au gi dans le fichier Uniprot. XPATH et XSL ne peuvent donc rien pour nous ici !

 

4. Expressions XPATH avancées (bioinformatique)

4.1 Valeur de CDD

Donner une transformation XSL qui permet d'obtenir la valeur du CDD pour une protéine du NCBI obtenue par efetch sachant qu'il s'agit du contenu texte de Object-id_id lorsque qu'on est dans un élément Dbtag dont le sous-élément Dbtag_db vaut 'CDD'. On utilisera le fichier 158513197.xml qui correspond à la protéine A1VFJ3 soit l'URL efetch...id=158513197. On devra trouver 111833 comme valeur de CDD (Conserved Domain Database). On pourra consulter 158513197_elts.txt qui est la sortie de xmlstarlet el -u 158513197.xml et 158513197_elts_Object-id_id.txt qui est la sortie de xmlstarlet el -u 158513197.xml | grep Object-id_id.

On essaiera de fournir plusieurs solutions, dont une qui utilise //Seq-feat_dbxref, une qui utilise //Object-id_id et une qui utilise //Dbtag.

4.2 Valeur de PFAM

Sur le site d'Uniprot, un fichier XML complet pour une protéine contient «quelque part» une indication de PFAM (Protein FAMilies). Rechercher cette valeur de PFAM pour la protéine X68357 soit le fichier P14602.xml dont les éléments sont listés dans P14602_elts.txt et les éléments avec attributs dans P14602_attrs.txt. On essaiera aussi de fournir plusieurs solutions. On devra trouver http://pfam.xfam.org/family/PF00011.

Solution :  

4.1 Valeur de CDD

Pour trouver le CDD, une première solution consiste à essayer de descendre dans l'arbre pour obtenir Object-id_id mais //Object-id_id est une notation ambigue qui sélectionne aussi bien //Org-ref_db/Dbtag/Dbtag_tag/Object-id/Object-id_id que //Seq-feat_dbxref/Dbtag/Dbtag_tag/Object-id/Object-id_id. Cette dernière expression fournit exactement ce que l'on cherche. La transformation XSL qui s'en déduit est classique : sélection de l'élément puis affichage du texte, soit ncbi_cdd1.xsl.

Une deuxième solution consiste à filtrer Object-id_id pour indiquer la base de données qui correspond à CDD. L'information de base de données est trois niveaux plus haut, donc on peut utiliser //Object-id_id[../../../Dbtag_db='CDD'] pour l'obtenir. Cette solution ncbi_cdd2.xsl est sans doute celle qui correspond le mieux à l'énoncé.

Une troisième solution est de filtrer Dbtag puis de descendre jusqu'à Object-id_id, soit : //Dbtag[Dbtag_db='CDD']/Dbtag_tag/Object-id/Object-id_id : ncbi_cdd3.xsl.

Une quatrième solution est de passer en revue dans une boucle tous les enfants de Dbtag. Lorsqu'on trouve un élément dont le nom est Dbtag_db et dont le texte est 'CDD', on remonte d'un niveau et on affiche le contenu de Dbtag_tag/Object-id/Object-id_id soit la transformation ncbi_cdd4.xsl.


     @ghchu~/public_html/Webrd|(~gH) > grep -i CDD 158513197.xml # dommage
     
     <Seq-annot_name>Annot:CDD</Seq-annot_name>
           <Annotdesc_name>CddSearch</Annotdesc_name>
                   <Object-id_str>CddInfo</Object-id_str>
                   <Object-id_str>cddScoreData</Object-id_str>
               <Dbtag_db>CDD</Dbtag_db>
                   <Object-id_str>cddScoreData</Object-id_str>
               <Dbtag_db>CDD</Dbtag_db>
     
     @ghchu~/public_html/Webrd|(~gH) > grep -3 -i CDD 158513197.xml # c'est mieux !
             </Seq-annot>
             <Seq-annot>
               <Seq-annot_db value="other">255</Seq-annot_db>
               <Seq-annot_name>Annot:CDD</Seq-annot_name>
               <Seq-annot_desc>
                 <Annot-descr>
                   <Annotdesc>
                     <Annotdesc_name>CddSearch</Annotdesc_name>
                   </Annotdesc>
                   <Annotdesc>
                     <Annotdesc_user>
                       <User-object>
                         <User-object_type>
                           <Object-id>
                             <Object-id_str>CddInfo</Object-id_str>
                           </Object-id>
                         </User-object_type>
                         <User-object_data>
     --
                       <User-object>
                         <User-object_type>
                           <Object-id>
                             <Object-id_str>cddScoreData</Object-id_str>
                           </Object-id>
                         </User-object_type>
                         <User-object_data>
     --
                     </Seq-feat_ext>
                     <Seq-feat_dbxref>
                       <Dbtag>
                         <Dbtag_db>CDD</Dbtag_db>
                         <Dbtag_tag>
                           <Object-id>
                             <Object-id_id>111833</Object-id_id>
     --
                       <User-object>
                         <User-object_type>
                           <Object-id>
                             <Object-id_str>cddScoreData</Object-id_str>
                           </Object-id>
                         </User-object_type>
                         <User-object_data>
     --
                     </Seq-feat_ext>
                     <Seq-feat_dbxref>
                       <Dbtag>
                         <Dbtag_db>CDD</Dbtag_db>
                         <Dbtag_tag>
                           <Object-id>
                             <Object-id_id>111833</Object-id_id>
     
     @ghchu~/public_html/Webrd|(~gH) > grep -i 111833 158513197.xml # un peu court
                             <Object-id_id>111833</Object-id_id>
                             <Object-id_id>111833</Object-id_id>
     
     @ghchu~/public_html/Webrd|(~gH) > grep -3 -i 111833 158513197.xml # voilà !
                         <Dbtag_db>CDD</Dbtag_db>
                         <Dbtag_tag>
                           <Object-id>
                             <Object-id_id>111833</Object-id_id>
                           </Object-id>
                         </Dbtag_tag>
                       </Dbtag>
     --
                         <Dbtag_db>CDD</Dbtag_db>
                         <Dbtag_tag>
                           <Object-id>
                             <Object-id_id>111833</Object-id_id>
                           </Object-id>
                         </Dbtag_tag>
                       </Dbtag>
     
     @ghchu~/public_html/Webrd|(~gH) > exsl 158513197.xml ncbi_cdd1.xsl
     111833 111833
     
     @ghchu~/public_html/Webrd|(~gH) > exsl 158513197.xml ncbi_cdd2.xsl
     11833 111833
     
     @ghchu~/public_html/Webrd|(~gH) > exsl 158513197.xml ncbi_cdd3.xsl
     111833 111833
     
     @ghchu~/public_html/Webrd|(~gH) > exsl 158513197.xml ncbi_cdd4.xsl
     111833;111833;
     

Voici les quatre transformations :

ncbi_cdd1.xsl       ncbi_cdd2.xsl       ncbi_cdd3.xsl       ncbi_cdd4.xsl       

4.2 Valeur de PFAM

Exercice volontairement corrigé de façon succinte :


     > grep -i -n PFAM P14602.xml
     
     484: <dbReference type="Pfam" id="PF00011">
     495: <dbReference type="SUPFAM" id="SSF49764">
     
     > xmlstarlet el -v P14602.xml | grep -i PFAM
     
     uniprot/entry/dbReference[@type='Pfam' and @id='PF00011']
     uniprot/entry/dbReference[@type='SUPFAM' and @id='SSF49764']
     
     > cat uniprot_pfam.xsl
     
           <?xml version="1.0" encoding="ISO-8859-1" ?>
           <!-- uniprot_pfam2.xsl -->
           <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
           <xsl:output method="text" />
     
           <xsl:template match="/">
             <xsl:apply-templates select="//dbReference[@type='Pfam']" />
           </xsl:template>
     
           <!-- ################################################## -->
     
           <xsl:template match="//dbReference[@type='Pfam']" >
             <xsl:value-of select="./@id" />
             <xsl:text> </xsl:text>
           </xsl:template>
     
           <!-- ################################################## -->
     
           </xsl:stylesheet>
     
     > exsl P14602.xml uniprot_pfam2.xsl
     PF00011
     
     

 

5. Compréhension de la transformation vide

Expliquer ce que fait la transformation vide sur les fichiers serv00.xml, serv01.xml... serv05.xml de la série 1 d'exercices, puis pour les fichiers pers01.xml, pers02.xml... pers04.xml de la série 1 d'exercices et enfin pour les fichiers fasta01.xml à fasta05.xml.

Solution :  

La transformation vide garde le contenu texte des éléments (et les espaces et les retours-charriots) mais pas les attributs :

serv00.xml       serv01.xml       serv02.xml       serv03.xml       serv04.xml       serv05.xml       

serv_00.txt       serv_01.txt       serv_02.txt       serv_03.txt       serv_04.txt       serv_05.txt       

pers01.xml       pers02.xml       pers03.xml       pers04.xml       

pers_01.txt       pers_02.txt       pers_03.txt       pers_04.txt       

fasta01.xml       fasta02.xml       fasta03.xml       fasta04.xml       fasta05.xml       

fasta_01.txt       fasta_02.txt       fasta_03.txt       fasta_04.txt       fasta_05.txt       

 

6. Comptages avec XSL (1)

Dans films2.xml, combien y a-t-il de films ? Et d'artistes ? Et de metteurs en scène ?

On écrira une transformation XSL qui affichera ces résultats en mode texte et qu'on exécutera avec xmlstarlet.

Solution :  

Compter avec XSL se fait à l'aide de la fonction count() dans un attribut select d'un élément xsl:value-of. Encore faut-il trouver les noeuds correspondants. Pour les films et les artistes, c'est assez simple car les éléments FILM et ARTISTE identifient de façon unique ce qu'on cherche donc il suffit de compter //FILM et //ARTISTE.

Pour trouver les metteurs en scène, il faut retenir les attributs id de ARTISTE qui correspondent à un attribut idref de MES, soit le filtre (déjà vu) ARTISTE[@id=//MES/@idref]. Nous avons rajouté dans la solution des xsl:text pour rendre les affichages plus lisibles et nous avons mis le nom des metteurs en majuscules (avec des indications de solution XSL 2) :


     <?xml version="1.0" encoding="ISO-8859-1" ?>
     <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="text" />
     
     <!-- fichier nbfilms0.xsl, s'applique à  films2.xml -->
     
     <xsl:template match="/">
     
     <xsl:text>Il y a </xsl:text>
     <xsl:value-of select="count(//FILM)" />
     <xsl:text> films dans films2.xml</xsl:text>
     
     <xsl:text> et </xsl:text>
     <xsl:value-of select="count(//ARTISTE)" />
     <xsl:text> artistes.
     </xsl:text>
     
     <xsl:value-of select="count(//MES)" />
     <xsl:text> références de metteurs en scènes sont utilisées pour </xsl:text>
                   <!-- ceci est du XSL 2 :
                         <xsl:value-of select="count(distinct-values(//MES))" />
                   -->
     <xsl:value-of select="count(//ARTISTE[./@id=//MES/@idref])" />
     <xsl:text> metteurs en scène distincts.
     </xsl:text>
     
     </xsl:template>
     
     <!-- fin de document -->
     </xsl:stylesheet>
     

     > xmlstarlet tr nbfilms0.xsl films2.xml
     
     Il y a 48 films dans films2.xml et 117 artistes.
     48 références de metteurs en scènes sont utilisées pour 32 metteurs en scène distincts.
     

 

7. Transformations entre éléments et attributs

Ecrire la transformation s2vers3.xsl qui transforme serv02.xml en serv03.xml, c'est-à-dire qui transforme les éléments en attributs. Ecrire ensuite la transformation inverse s3vers2.xsl qui transforme serv03.xml en serv02.xml, c'est-à-dire qui transforme les attributs en éléments.

Solution :  

Avec xsl:attribute on crée un attribut et avec xsl:element on crée un élément. Donc il suffit de se positionner sur chacun des services et le tour est joué ! On remarquera l'utilisation de normalize-space pour s2vers3.xsl.


     <?xml version="1.0"  encoding="ISO-8859-1" ?>
     <!-- fichier s2vers3.xsl -->
     <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="xml" />
     
     <xsl:template match="/">
     <xsl:text>
     </xsl:text>
     <services>
        <xsl:apply-templates select="//service" />
     </services>
     </xsl:template>
     
     <xsl:template match="service">
     <service>
      <xsl:attribute name="nomDeService">
        <xsl:value-of select="normalize-space(nomDeService)" />
      </xsl:attribute>
     </service>
     <xsl:text>
     </xsl:text>
     </xsl:template>
     
     </xsl:stylesheet>
     

     @ghchu~/public_html/Webrd|(~gH) > cat serv02.xml
     <?xml version="1.0" encoding="ISO-8859-1"?>
     <!-- serv02.xml -->
     <services>
       <service><nomDeService>Achats</nomDeService></service>
       <service><nomDeService>Direction</nomDeService></service>
       <service>
          <nomDeService>
            Courrier
          </nomDeService>
       </service>
       <service><nomDeService>Direction</nomDeService></service>
       <service><nomDeService>Repr\ufffdsentation</nomDeService></service>
     </services>
     
     @ghchu~/public_html/Webrd|(~gH) > exsl serv02.xml s2vers3.xsl
     <?xml version="1.0" encoding="UTF-8"?>
     <services><service nomDeService="Achats"/>
     <service nomDeService="Direction"/>
     <service nomDeService="Courrier"/>
     <service nomDeService="Direction"/>
     <service nomDeService="Représentation"/>
     </services>
     

     <?xml version="1.0"  encoding="ISO-8859-1" ?>
     <!-- fichier s3vers2.xml -->
     <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="xml" />
     
     <xsl:template match="/">
     <xsl:text>
     </xsl:text>
     <services>
        <xsl:apply-templates select="//service" />
     </services>
     </xsl:template>
     
     <xsl:template match="service">
     <service>
     <xsl:element name="nomDeService">
        <xsl:value-of select="@nomDeService" />
     </xsl:element>
     </service>
     <xsl:text>
     </xsl:text>
     </xsl:template>
     
     </xsl:stylesheet>
     

     @ghchu~/public_html/Webrd|(~gH) > cat serv03.xml
     <?xml version="1.0" encoding="ISO-8859-1"?>
     <!-- serv03.xml -->
     <services>
       <service nomDeService="Achats"></service>
       <service nomDeService="Direction" />
       <service
          nomDeService="Courrier"
       >
       </service>
       <service nomDeService="Direction"/> <!-- coll\ufffd ! -->
       <service nomDeService="Représentation" />
     </services>
     
     @ghchu~/public_html/Webrd|(~gH) > exsl serv03.xml s3vers2.xsl
     <?xml version="1.0" encoding="UTF-8"?>
     <services><service><nomDeService>Achats</nomDeService></service>
     <service><nomDeService>Direction</nomDeService></service>
     <service><nomDeService>Courrier</nomDeService></service>
     <service><nomDeService>Direction</nomDeService></service>
     <service><nomDeService>Représentation</nomDeService></service>
     </services>
     

 

8. Ajouts et modifications d'éléments ou d'attributs

Ecrire des transformations ajouteAge qui calculent et ajoutent l'age aux personnes dont on connait la date de naissance. On ajoutera un élément age lorsque la ddn est un élément, un attribut age si la ddn est un attribut. Effectuez ensuite les transformations inverses, à savoir mettre un attribut quand on a un élément et réciproquement.

Effectuez des transformations similaires pour ajouter la longueur d'une séquence Fasta pour les fichiers bioinformatiques.

Nous avions vu dans la série 2 d'exercices qu'un attribut tout numérique ne pouvait pas servir d'ID et donc d'IDREF non plus. Ecrire une transformation ajouteArt qui modifie les attributs id et idref des éléments MES (metteurs en scène) et ARTISTES de films2.xml par l'ajout de "art". Ainsi au lieu de <MES idref="3"></MES> et <ARTISTE id="51">, on devra avoir : <MES idref="art3"></MES> et <ARTISTE id="art51">.

Solution :  

8.1 Ajout de l'age

Commençons par ajouter un élément age pour pers01.xml :


     <?xml version="1.0"  encoding="ISO-8859-1" ?>
     <!-- fichier aea1.xsl -->
     <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="xml" />
     
     <xsl:template match="/">
     
     <xsl:text>
     </xsl:text>
     <personnes>
     <xsl:text>
     </xsl:text>
      <xsl:apply-templates select="//personne" />
     </personnes>
     </xsl:template>
     
     <xsl:template match="personne">
     <personne>
       <xsl:copy-of select="./*" />
       <age><xsl:value-of select="2013-ddn"/></age>
     </personne>
     <xsl:text>
     </xsl:text>
     </xsl:template>
     
     </xsl:stylesheet>
     

Résultat :


     <?xml version="1.0" encoding="UTF-8"?>
     <personnes>
     <personne><nom>DUPUIS</nom><prénom>Isabelle</prénom><ddn>1965</ddn><age>48</age></personne>
     <personne><nom>DUPONT</nom><prénom>Jean</prénom><ddn>1963</ddn><age>50</age></personne>
     <personne><nom>DUPONT</nom><prénom>Jack</prénom><ddn>1968</ddn><age>45</age></personne>
     </personnes>
     

Ajoutons maintenant un attribut age pour pers02.xml :


     <?xml version="1.0"  encoding="ISO-8859-1" ?>
     <!-- fichier aea2.xsl -->
     <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="xml" />
     
     <xsl:template match="/">
     
     <xsl:text>
     </xsl:text>
     <personnes>
        <xsl:apply-templates select="//personne" />
     <xsl:text>
     </xsl:text>
     </personnes>
     </xsl:template>
     
     <xsl:template match="personne">
     <xsl:text>
     </xsl:text>
     <personne>
       <xsl:copy-of select="@*" />
       <xsl:attribute name="age">
         <xsl:value-of select="2013-@ddn"/>
       </xsl:attribute>
     </personne>
     </xsl:template>
     
     </xsl:stylesheet>
     

Résultat :


     <?xml version="1.0" encoding="UTF-8"?>
     <personnes>
     <personne ddn="1965" nom="DUPUIS" prénom="Isabelle" age="48"/>
     <personne ddn="1963" nom="DUPONT" prénom="Jean" age="50"/>
     <personne ddn="1968" nom="DUPONT" prénom="Jack" age="45"/>
     </personnes>
     

Sur le même pricipe; ajoutons maintenant un attribut age pour pers01.xml :


     <?xml version="1.0"  encoding="ISO-8859-1" ?>
     <!-- fichier aea3.xsl -->
     <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="xml" />
     
     <xsl:template match="/">
     
     <xsl:text>
     </xsl:text>
     <personnes>
     <xsl:text>
     </xsl:text>
      <xsl:apply-templates select="//personne" />
     </personnes>
     </xsl:template>
     
     <xsl:template match="personne">
     <personne>
       <xsl:attribute name="age"><xsl:value-of select="2013-ddn"/></xsl:attribute>
       <xsl:copy-of select="./*" />
     </personne>
     <xsl:text>
     </xsl:text>
     </xsl:template>
     
     </xsl:stylesheet>
     

Résultat :


     <?xml version="1.0" encoding="UTF-8"?>
     <personnes>
     <personne age="48"><nom>DUPUIS</nom><prénom>Isabelle</prénom><ddn>1965</ddn></personne>
     <personne age="50"><nom>DUPONT</nom><prénom>Jean</prénom><ddn>1963</ddn></personne>
     <personne age="45"><nom>DUPONT</nom><prénom>Jack</prénom><ddn>1968</ddn></personne>
     </personnes>
     

Et enfin voici un élément age pour pers02.xml :


     <?xml version="1.0"  encoding="ISO-8859-1" ?>
     <!-- fichier aea4.xsl -->
     <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="xml" />
     
     <xsl:template match="/">
     
     <xsl:text>
     </xsl:text>
     <personnes>
        <xsl:apply-templates select="//personne" />
     <xsl:text>
     </xsl:text>
     </personnes>
     </xsl:template>
     
     <xsl:template match="personne">
     <xsl:text>
     </xsl:text>
     <personne>
       <xsl:copy-of select="@*" />
       <xsl:element name="age">
         <xsl:value-of select="2013-@ddn"/>
       </xsl:element>
     </personne>
     </xsl:template>
     
     </xsl:stylesheet>
     

Résultat :


     <?xml version="1.0" encoding="UTF-8"?>
     <personnes>
     <personne ddn="1965" nom="DUPUIS" prénom="Isabelle"><age>48</age></personne>
     <personne ddn="1963" nom="DUPONT" prénom="Jean"><age>50</age></personne>
     <personne ddn="1968" nom="DUPONT" prénom="Jack"><age>45</age></personne>
     </personnes>
     

8.2 Ajout de la longueur dans les séquences Fasta

Voici deux possibilités d'ajout, d'abord en élément puis en attribut :


     <?xml version="1.0" encoding="ISO-8859-1" ?>
     <xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version="1.0">
     <!-- Fichier eltaddlng.xsl -->
     
     <!-- on passe de
        <protein>
          <identifiant>A2ZDX4</identifiant>
          <class>1</class>
          <sequence>
          ...
        ?
        <protein>
          <identifiant>A2ZDX4</identifiant>
          <class>1</class>
          <longueur>171</longueur>
          <sequence>
          ...
     -->
     
     <!-- le fichier inclus contient entre autres sdl (saut de ligne) -->
     <xsl:import href="stdWeb.xsl" />
     
     <xsl:output method="xml" encoding="UTF-8" />
     
     <xsl:template match="proteins">
        <proteins>
           <xsl:call-template name="sdl" />
           <xsl:for-each select="protein">
              <protein>
                 <xsl:call-template name="sdl" />
                 <identifiant>
                    <xsl:value-of select="identifiant" />
                 </identifiant>
                 <xsl:call-template name="sdl" />
                 <class>
                    <xsl:value-of select="class" />
                 </class>
                 <xsl:call-template name="sdl" />
                 <longueur>
                    <xsl:value-of select="string-length(sequence)" />
                 </longueur>
                 <xsl:call-template name="sdl" />
                 <sequence>
                    <xsl:value-of select="sequence" />
                 </sequence>
                 <xsl:call-template name="sdl" />
              </protein>
              <xsl:call-template name="sdl" />
           </xsl:for-each>
        </proteins>
     </xsl:template>
     </xsl:stylesheet>
     

     <?xml version="1.0" encoding="ISO-8859-1" ?>
     <xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version="1.0">
     <!-- Fichier attaddlngv2.xsl -->
     
     <!-- on passe de
        <protein>
          <identifiant>A2ZDX4</identifiant>
          <class num="1" />
          <sequence>
          ...
        ?
        <protein>
          <identifiant>A2ZDX4</identifiant>
          <class>1</class>
          <sequence longueur="171">
          ...
     -->
     
     <!-- le fichier inclus contient entre autres sdl (saut de ligne) -->
     <xsl:import href="stdWeb.xsl" />
     
     <xsl:output method="xml" encoding="UTF-8" />
     
     <xsl:template match="proteins">
        <proteins>
           <xsl:call-template name="sdl" />
           <xsl:for-each select="protein">
              <protein>
                 <xsl:call-template name="sdl" />
                 <identifiant>
                    <xsl:value-of select="identifiant" />
                 </identifiant>
                 <xsl:call-template name="sdl" />
                 <class>
                    <xsl:value-of select="class/@num" />
                 </class>
                 <xsl:call-template name="sdl" />
     
     <!--
     
          ## ce qui suit n'est pas optimis? car on utilise deux fois translate()
     
                 <xsl:element name="sequence">
                    <xsl:attribute name="longueur">
                       <xsl:value-of select="string-length(translate(sequence,' ',''))" />
                    </xsl:attribute>
                    <xsl:value-of select="translate(sequence,' ','')" />
                 </xsl:element>
     
          ## il vaut mieux d?finir une variable qui contient le r?sultat de translate :
     
     -->
                 <xsl:variable name="nouvelleSequence" select="translate(./sequence,' ','')" />
                 <xsl:element name="sequence">
                    <xsl:attribute name="longueur">
                       <xsl:value-of select="string-length($nouvelleSequence)" />
                    </xsl:attribute>
                    <xsl:value-of select="$nouvelleSequence" />
                 </xsl:element>
                 <xsl:call-template name="sdl" />
              </protein>
              <xsl:call-template name="sdl" />
           </xsl:for-each>
        </proteins>
     </xsl:template>
     </xsl:stylesheet>
     

8.3 Ajout de "art" pour les id et idrefs


     <?xml version="1.0"  encoding="ISO-8859-1" ?>
     <!-- fichier ajoutart.xsl -->
     <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="xml" />
     
     <xsl:template match="/">
     
     <xsl:text>
     </xsl:text>
     <FILMSETARTISTES>
     <xsl:text>
     </xsl:text>
      <xsl:apply-templates select="//FILM" />
      <xsl:apply-templates select="//ARTISTE" />
     </FILMSETARTISTES>
     </xsl:template>
     
     <xsl:template match="ARTISTE">
     <ARTISTE>
       <xsl:attribute name="id">
          <xsl:value-of select='concat("art",@id)' />
       </xsl:attribute>
       <xsl:copy-of select="*" />
     </ARTISTE>
     <xsl:text>
     </xsl:text>
     </xsl:template>
     
     <xsl:template match="FILM">
     <FILM>
       <xsl:for-each select="*">
          <xsl:choose>
            <xsl:when test="position()=4">
              <xsl:element name="MES">
               <xsl:attribute name="idref">
                 <xsl:value-of select='concat("art",@idref)' />
               </xsl:attribute>
              </xsl:element>
     <xsl:text>
     </xsl:text>
            </xsl:when>
            <xsl:otherwise>
              <xsl:copy-of select="." />
            </xsl:otherwise>
          </xsl:choose>
       </xsl:for-each>
     </FILM>
     <xsl:text>
     </xsl:text>
     </xsl:template>
     
     <xsl:template match="MES">
     <MES>
       <xsl:attribute name="idref">
          <xsl:value-of select='concat("art",@idref)' />
       </xsl:attribute>
     </MES>
     </xsl:template>
     
     </xsl:stylesheet>
     

 

9. Comptages avec XSL (2)

On reprend ici l'exercice 6 avec les comptages de personnes dans les films en XSL. Dans films2.xml, combien y a-t-il de films ? Et d'artistes ? Et de metteurs en scène ?

On écrira une transformation XSL qui affichera ces résultats en mode texte et qu'on exécutera avec xmlstarlet. On affichera également la liste des seuls metteurs en scène avec nom et prénom, le nom étant écrit en majuscules.

Que faut-il modifier pour trier la liste des metteurs en scène par ordre alphabétique ?

Solution :  

Pour avoir une liste triée, il suffit d'utiliser xsl:sort et de préciser sur quel élément faire porter le tri, même si ici on pourra de dispenser du select puisque ARTNOM est le premier élément d'ARTISTE. La solution est donc ici et ci-dessous :


     <?xml version="1.0" encoding="ISO-8859-1" ?>
     <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="text" />
     
     <!-- s'applique à  films2.xml -->
     
     <xsl:template match="/">
     
     <xsl:text>Il y a </xsl:text>
     <xsl:value-of select="count(//FILM)" />
     <xsl:text> films dans films2.xml</xsl:text>
     
     <xsl:text> et </xsl:text>
     <xsl:value-of select="count(//ARTISTE)" />
     <xsl:text> artistes.
     </xsl:text>
     
     <xsl:value-of select="count(//MES)" />
     <xsl:text> références de metteurs en scènes sont utilisées pour </xsl:text>
                   <!-- ceci est du XSL 2 :
                         <xsl:value-of select="count(distinct-values(//MES))" />
                   -->
     <xsl:value-of select="count(//ARTISTE[@id=//MES/@idref])" />
     <xsl:text> metteurs en scène distincts dont voici la liste :
     </xsl:text>
     
     <!--
     
     # ancienne version (sans tri) :
     
     <xsl:apply-templates select="//ARTISTE[./@id=//MES/@idref]" />
     
     
     # nouvelle version minimale (avec tri) :
     
     <xsl:apply-templates select="//ARTISTE[./@id=//MES/@idref]" >
       <xsl:sort />
     </xsl:apply-templates>
     
     # solution conseillée (plus robuste)
     -->
     
     <xsl:apply-templates select="//ARTISTE[./@id=//MES/@idref]" >
       <xsl:sort select="ARTNOM" />
     </xsl:apply-templates>
     
     </xsl:template>
     
     <xsl:template match="ARTISTE" >
     <xsl:text>    </xsl:text>
     <xsl:value-of select="ARTPRENOM" />
     <xsl:text> </xsl:text>
                   <!-- ceci est du XSL 2 :
                         <xsl:value-of select="upper-case(ARTNOM)" />
                   -->
     <xsl:value-of select="translate(ARTNOM,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />
     <xsl:text>
     </xsl:text>
     </xsl:template>
     
     <!-- fin de document -->
     </xsl:stylesheet>
     

     xmlstarlet tr nbfilms.xsl films2.xml
     
     Il y a 48 films dans films2.xml et 117 artistes.
     48 références de metteurs en scènes sont utilisées pour 32 metteurs en scène distincts dont voici la liste :
         Jean-Jacques ANNAUD
         Luc BESSON
         Tim BURTON
         James CAMERON
         Brenda CHAPMAN
         Brian DE PALMA
         Jonathan DEMME
         Clint EASTWOOD
         Roland EMMERICH
         Bobby FARRELLY
         David FINCHER
         Terry GILLIAM
         Jean GIRAULT
         Renny HARLIN
         Alfred HITCHCOCK
         Stanley KUBRICK
         Akira KUROZAWA
         Patrice LECONTE
         Barry LEVINSON
         Richard MARQUAND
         John MCTIERMAN
         Sam MENDES
         Hervé PALUD
         Marie PERNNOU
         Maurice PIALAT
         Ridley SCOTT
         Tony SCOTT
         Steven SPIELBERG
         Quentin TARANTINO
         Andrei TARKOVSKI
         Andy WACHOWSKI
         John WOO
     
     

 

10. Suppression de la mise en forme XHTML

Expliquez ce que font chacune des transformations suivantes et ce qu'on obtient si on les applique au fichier serv00.xml :

services01.xsl       services02.xsl       services03.xsl       services04.xsl       services05.xsl       

Ecrire une transformation nohtml.xsl qui ne garde que les contenus-textes de la partie <body> d'une page XHTML valide. On pourra utiliser page.html qui devra être transformé en page.txt.

Solution :  

Solution volontairement non communiquée.

 

11. Tris avec XSL

Afficher tous les films de films2.xml par ordre alphabétique dans un fichier texte.

Afficher tous les films et leur date de sortie de films2.xml dans une page XHTML "presque" valide. On triera par date de sortie décroissante et, en cas d'ex-aequo, par ordre alphabétique, comme par exemple pour l'année 1990.

Afficher tous les artistes de films2.xml qui ont joué dans au moins un film dans une page XHTML valide au sens 1.0 strict avec un encodage ISO-8859-1. On fournira leur nom, leur prénom, le nombre de films où ils ont joué et on triera par nom puis par prénom en cas d'égalité. Rappel : certains artistes sont des metteurs en scène qui ne jouent pas tous dans des films.

Solution :  

Le premier tri est très facile à réaliser car il n'y a qu'une seule clé de tri. Il suffit donc d'ajouter xsl:sort dans la règle de sélection des //TITRE pour obtenir la liste demandée, soit films_lst_1.xsl.

Pour la deuxième transformation, il y a deux problèmes distincts : le tri multicritères et la production d'un tableau XHTML. Pour trier selon l'année puis selon le texte du titre, il suffit donc d'enchainer les xsl:sort (il ne faut pas les emboiter), soit films_lst_2a.xsl. Pour la partie partie XHTML, on pourrait penser écrire un sous-programme pour la partie entre <html> et <body> nommé debutPage puis un sous-programme pour </body> et </html; nommé finPage, soit films_lst_2b1.xsl mais malheureusement, cela n'est pas possible car il faudrait laisser <body> ouvert. Il faut donc se rabattre sur une solution plus classique, moins modulaire avec films_lst_2b2.xsl qui produit films2b2.html

La troisième transformation ajoute le problème de la validité de la page et celui du nombre de films joués par acteur. Attention : tous les artistes ne sont pas des acteurs, car certains sont des metteurs en scène. Si essaie de compter le nombre de films par artiste, on doit, à partir du nom de l'artiste, trouver son prénom, ce qui est facile puis qu'il suffit de remonter d'un cran dans l'arbre puis d'utiliser l'élément ARTPRENOM. Par contre, pour compter, il faut se servir du noeud courant avec ARTNOM et ARTPRENOM et comparer à tous les NOM et PRENOM des films. Une solution correspondante est dans films_lst_3a.xsl. Le résultat de la transformation est dans films_lst_3a.txt.

Pour ne prendre en compte que les artistes qui ont joué dans au moins un film, on peut se contenter de filtrer l'affichage précédent suivant que le comptage avec count() renvoie un nombre supérieur à 0 ou pas, soit films_lst_3b.xsl. Le résultat de cette transformation est dans films_lst_3b.txt.

Il reste maintenant à fournir une page XHTML valide au sens 1.0 strict en ISO-8859-1. Le plus simple est sans doute de produire les élements XHTML via xsl:value-of avec l'attribut disable-output-escaping mis à yes, soit films_lst_3c.xsl. Le résultat de cette transformation est dans films_lst_3c.html.

Après réflexion, il n'y a pas besoin de disable-output-escaping='yes' pour les éléments complets, et on peut donc simplifier la transformation en films_lst_3d.xsl où toute la partie head est écrite telle quelle. Le résultat de cette transformation est dans films_lst_3d.html.

films_lst_1.xsl       films_lst_2a.xsl       films_lst_2b.xsl       films_lst_3a.xsl       films_lst_3b.xsl       films_lst_3c.xsl       films_lst_3d.xsl       

 

12. Fichiers inclus, sous-programmes et variables en XSL

Reprendre la transformation films_lst_3d.xsl : on mettra sdl, debutPage et finPage dans le fichier stdWeb.xsl. Le titre de la page, rapellé dans un <h1> en haut de page sera bien sûr passé en paramètre.

Ecrire une transformation XSL qui produit un tableau XHTML des films (en ignorant les roles et le résumé ; on mettra le titre en dernière colonne) et un tableau XHTML des artistes, avec une table des matières en haut de page, comme dans la page fa.html. Pour que ce soit plus facile à lire, on définira les fichiers tabFilms.xsl et tabArtistes.xsl. On modifiera stdWeb.xsl pour que la redite du titre en <h1> en haut de page soit facultative.

Attention : certains films n'ont pas de GENRE et certains artistes n'ont pas de ANNEENAISS.

Solution :  

Pour inclure un fichier XSL, on a le choix entre xsl:import et xsl:include. Les parties à inclure sont des sous-progammes "propres", donc on utilise xsl:import qui doit être le premier enfant de xsl:stylesheet. Les paramètres sont définis via xsl:param, ils sont déclarés par xsl:with-param et on les utilise à l'aide de la notation $ un peu comme en PHP. Au final, le fichier à inclure est stdWeb.xsl, la transformation est films_lst_4.xsl et son résultat films_lst_4.html.

Pour produire deux tableaux, on définit deux "templates" qui chacune appellent debutTableau et finTableau. Voici, à titre indicatif, via le fichier stdWeb2.xsl comment on peut paramétrer ces «sous-programmes» y compris la redite éventuelle de en <h1> en haut de page dans debutPage.


     <?xml version="1.0" encoding="ISO-8859-1" ?>
     <xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version="1.0">
     <xsl:output method="xml" encoding="ISO-8859-1"/>
     
     <!-- ceci est le fichier stdWeb.xsl  -->
     
     <!-- il contient des sous-programmes pour faciliter les transformations  -->
     <!-- XSL qui produisent des pages XHTML valides au sens 1.0 Strict       -->
     
     <!-- ########################################################################### -->
     
     <!-- début de page XHTML -->
     
     <!-- ########################################################################### -->
     
     <xsl:template name="debutPage">
     
        <xsl:param name="leTitre"  />
        <xsl:param name="h1redite" />
     
        <xsl:value-of select="'&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;'"
                                                disable-output-escaping="yes" />    <xsl:call-template name="sdl" />
        <xsl:value-of select="'&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; lang=&quot;fr&quot; xml:lang=&quot;fr&quot;&gt;'"
                                                  disable-output-escaping="yes" />    <xsl:call-template name="sdl" />
        <head>                                                                        <xsl:call-template name="sdl" />
          <meta http-equiv="Content-type" content="text/html; charset=iso-8859-1"/>   <xsl:call-template name="sdl" />
          <link  rel="stylesheet" type="text/css" href="std.css" title="gh"/>         <xsl:call-template name="sdl" />
          <title><xsl:value-of select="$leTitre" /></title>                           <xsl:call-template name="sdl" />
        </head>                                                                       <xsl:call-template name="sdl" />
     
        <xsl:value-of select="'&lt;body class=&quot;beige_jpg&quot;&gt;'"     disable-output-escaping="yes" />    <xsl:call-template name="sdl" />
        <xsl:value-of select="'&lt;blockquote&gt;'"     disable-output-escaping="yes" />    <xsl:call-template name="sdl" />
     
        <xsl:if test="$h1redite='yes'">
           <h1><xsl:value-of select="$leTitre" /></h1><xsl:call-template name="sdl" />
        </xsl:if>
     
     </xsl:template>
     
     <!-- ########################################################################### -->
     
     <!-- fin de page XHTML -->
     
     <!-- ########################################################################### -->
     
     <xsl:template name="finPage">
        <xsl:value-of select="'&lt;/blockquote&gt;'" disable-output-escaping="yes" />    <xsl:call-template name="sdl" />
        <xsl:value-of select="'&lt;/body&gt;'"        disable-output-escaping="yes" />    <xsl:call-template name="sdl" />
        <xsl:value-of select="'&lt;/html&gt;'"        disable-output-escaping="yes" />    <xsl:call-template name="sdl" />
     </xsl:template>
     
     <!-- ########################################################################### -->
     
     <!-- début de section -->
     
     <!-- ########################################################################### -->
     
     <xsl:template name="debutSection">
        <xsl:value-of select="'&lt;table cellpadding=&quot;50&quot; class=&quot;bgcolor_white&quot; width=&quot;90%&quot;
                             summary=&quot;cadre général&quot;&gt;&lt;tr&gt;&lt;td class=&quot;bgcolor_white&quot;&gt;'"
        disable-output-escaping="yes" />    <xsl:call-template name="sdl" />
     </xsl:template>
     
     <!-- ########################################################################### -->
     
     <!-- fin de section -->
     
     <xsl:template name="finSection">
        <xsl:value-of select="'&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;'" disable-output-escaping="yes" />    <xsl:call-template name="sdl" />
     </xsl:template>
     
     <!-- ########################################################################### -->
     
     <!-- début de tableau XHTML -->
     
     <!-- ########################################################################### -->
     
     <xsl:template name="debutTableau">
        <xsl:value-of select="'&lt;table border=&quot;1&quot; class=&quot;bgcolor_white collapse&quot; cellpadding=&quot;20&quot; cellspacing=&quot;5&quot;&gt;'"
                      disable-output-escaping="yes"
        />
        <xsl:call-template name="sdl" />
     </xsl:template>
     
     <!-- ########################################################################### -->
     
     <!-- fin de tableau XHTML -->
     
     <!-- ########################################################################### -->
     
     <xsl:template name="finTableau">
        <xsl:value-of select="'&lt;/table&gt;'" disable-output-escaping="yes" />
        <xsl:call-template name="sdl" />
     </xsl:template>
     
     <!-- ########################################################################### -->
     
     <!-- saut de ligne -->
     
     <!-- ########################################################################### -->
     
     <xsl:template name="sdl">
     <xsl:text>
     </xsl:text>
     </xsl:template>
     
     <!-- ########################################################################### -->
     
     </xsl:stylesheet>
     

La programmation XSL est donc verbeuse, à défaut d'être difficile. Voici le «programme principal» qui est dans films_lst_5.xsl :


     <?xml version="1.0" encoding="ISO-8859-1" ?>
     <xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version="1.0">
     <xsl:import href="stdWeb2.xsl" />
     <xsl:import href="presentation.xsl" />
     <xsl:import href="tabFilms.xsl" />
     <xsl:import href="tabArtistes.xsl" />
     <xsl:output method="xml" encoding="ISO-8859-1"/>
     
     <!-- ceci est le fichier films_lst_5.xsl  -->
     
     <xsl:template match="/">
     
       <xsl:call-template name="debutPage">
          <xsl:with-param name="leTitre">Films et artistes avec table des matières</xsl:with-param>
          <xsl:with-param name="h1redite">no</xsl:with-param>
       </xsl:call-template>
       <xsl:call-template name="debutSection" />
     
       <blockquote>
     
          <h1>Films et artistes, table des Matières</h1>
          <blockquote>
            <dl>
              <dt><a href="#films">Tableau des films</a></dt>
              <dd>
              <p>
                Avec année de parution, genre, pays, metteur en scène et titre.
              </p>
              </dd>
              <dt><a href="#artistes">Tableau des artistes</a></dt>
              <dd>
              <p>
               Soit : nom, prénom, date de naissance.
              </p>
              </dd>
            </dl>
          </blockquote>
     
          <xsl:call-template name="presentation" />
     
          <xsl:call-template name="tableauDesFilms" />
     
          <xsl:call-template name="tableauDesArtistes" />
     
       </blockquote>
     
       <xsl:call-template name="finSection" />
       <xsl:call-template name="finPage" />
     
     </xsl:template>
     
     </xsl:stylesheet>
     

Et l'un des deux «sous-programmes» tableauDesFilms qui est dans tabFilms.xsl :


     <?xml version="1.0" encoding="ISO-8859-1" ?>
     <xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version="1.0">
     <xsl:output method="xml" encoding="ISO-8859-1"/>
     
     <!-- ceci est le fichier tabFilms.xsl  -->
     
     <!-- ########################################################################### -->
     
     <xsl:template name="tableauDesFilms">
     
       <h2><a name="films">Tableau des films    </a></h2>
     
       <xsl:call-template name="debutTableau" />
       <tr>
         <th>Année</th>
         <th>Titre</th>
         <th>Genre</th>
         <th>Pays</th>
       </tr>
       <xsl:apply-templates select="//FILM" />
       <xsl:call-template name="finTableau" />
     
     </xsl:template>
     
     <!-- ########################################################################### -->
     
     <xsl:template match="FILM">
       <tr>
         <td align="right"><xsl:value-of select="@Annee" /></td>
         <td><xsl:value-of select="TITRE" /></td>
         <td>
           <xsl:choose>
             <xsl:when test="GENRE !=''">
                 <xsl:value-of select="GENRE" />
             </xsl:when>
             <xsl:otherwise>
                  <span class="grouge">(non su)</span>
             </xsl:otherwise>
           </xsl:choose>
         </td>
         <td><xsl:value-of select="PAYS" /></td>
       </tr>
     </xsl:template>
     
     <!-- ########################################################################### -->
     
     </xsl:stylesheet>
     

Pour que la solution soit complète, il reste à consulter les deux autres fichiers importés, à savoir presentation.xsl et tabArtistes.xsl. Au bout du compte, l'application de films_lst_5.xsl à films2.xml aboutit donc à fa.html, soit, sur le serveur, films5xsl (sans images ni style, volontairement), ou encore : films2+tableaux.

stdWeb.xsl       films_lst_4.xsl       films_lst_5.xsl       stdWeb2.xsl       presentation.xsl       tabFilms.xsl       tabArtistes.xsl       

 

13. Une transformation à peine plus complexe

On voudrait transférer films2.xml dans une base de données FA (Films et Artistes), sans les roles ni le résumé. On dispose des instructions MySql suivantes pour recréer les tables de la base (fichier fa.mysql) :


     # on suppose que la base "fa" a déjà été créée
     
     USE fa ;
     
     ###################################################################
     #
     # les films
     #
     ###################################################################
     
     DROP   TABLE IF EXISTS films ;
     
     CREATE TABLE films (
     
       idFilm INT(5)      NOT NULL ,
       annee  INT(4)      NOT NULL ,
       genre  VARCHAR(10) NOT NULL ,
       pays   VARCHAR(20) NOT NULL ,
       mes    INT(5)      NOT NULL ,
       titre  VARCHAR(80) NOT NULL ,
     
       PRIMARY KEY ( idFilm)
     
     ) ; # fin pour films
     
     ###################################################################
     #
     # les artistes
     #
     ###################################################################
     
     DROP   TABLE IF EXISTS artistes ;
     
     CREATE TABLE artistes (
     
       idArtiste   INT(5)      NOT NULL ,
       artnom      VARCHAR(30) NOT NULL ,
       artprenom   VARCHAR(30) NOT NULL ,
       anneenaiss  INT(4)      NOT NULL ,
     
       PRIMARY KEY ( idArtiste)
     
     ) ; # fin pour artistes
     
     # pour test :
     
     ## INSERT INTO films    (idFilm, annee, genre, pays, mes, titre)  VALUES (1,1958,"Drame","USA",3,"Vertigo") ;
     ## INSERT INTO artistes (idArtiste, artnom, artprenom,anneenaiss) VALUES (6,"Cameron","James",1954)         ;
     
     

Ecrire une transformation XSL qui remplit la base.

Attention  là encore au fait que certains films n'ont pas de GENRE et que certains artistes n'ont pas de ANNEENAISS.

Et pour finir, reprendre l'exercice qui produit les deux tableaux XHTML stricts (fa.html) et rajouter un lien vers le metteur en scène sous la date de parution. On générera des id pour chacun des metteurs en scène.

Solution :  

Il n'y a pas vraiment de difficultés ici, sauf à définir le champ idFilm car pour la tables artistes, on dispose de la valeur de ARTISTE//@id. Au final, voici donc la solution dans fa.xsl.


     <?xml version="1.0" encoding="ISO-8859-1" ?>
     <xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version="1.0">
     <xsl:import href="stdWeb2.xsl" />
     <xsl:output method="text" encoding="ISO-8859-1"/>
     
     <!-- ceci est le fichier fa.xsl  -->
     
     <!-- ########################################################################### -->
     
     <xsl:template match="/">
     
        <xsl:apply-templates select="//ARTISTE" />
     
        <xsl:call-template name="sdl" />
        <xsl:call-template name="sdl" />
     
        <xsl:apply-templates select="//FILM" />
     
        <xsl:call-template name="sdl" />
        <xsl:call-template name="sdl" />
     
        <xsl:text>
     
        # pour vérification :
        select * from films   limit 10 ;
        select * from artistes limit 10 ;
     
        </xsl:text>
     
     </xsl:template>
     
     <!-- ########################################################################### -->
     
     <xsl:template match="ARTISTE">
     
       <xsl:text>INSERT INTO artistes (idArtiste, artnom, artprenom,anneenaiss) VALUES (</xsl:text>
       <xsl:value-of select="@id" /><xsl:text>, </xsl:text>
       <xsl:text>"</xsl:text><xsl:value-of select="ARTNOM"     /><xsl:text>",</xsl:text>
       <xsl:text>"</xsl:text><xsl:value-of select="ARTPRENOM"  /><xsl:text>",</xsl:text>
       <xsl:choose>
          <xsl:when test="ANNEENAISS !=''">
             <xsl:value-of select="ANNEENAISS" />
          </xsl:when>
          <xsl:otherwise>
             <xsl:text>0000</xsl:text>
          </xsl:otherwise>
       </xsl:choose>
       <xsl:text>) ; </xsl:text>
       <xsl:call-template name="sdl" />
     
     </xsl:template>
     
     <!-- ########################################################################### -->
     
     <xsl:template match="FILM">
     
       <xsl:text>INSERT INTO films (idFilm,annee, genre, pays, mes, titre)  VALUES (</xsl:text>
       <xsl:value-of select="position()" /><xsl:text>, </xsl:text>
       <xsl:value-of select="@Annee" /><xsl:text>, </xsl:text>
       <xsl:text>"</xsl:text>
       <xsl:choose>
          <xsl:when test="GENRE !=''">
             <xsl:value-of select="GENRE" />
          </xsl:when>
          <xsl:otherwise>
             <xsl:text>(non su)</xsl:text>
          </xsl:otherwise>
       </xsl:choose>
       <xsl:text>",</xsl:text>
       <xsl:text>"</xsl:text><xsl:value-of select="PAYS"          /><xsl:text>",</xsl:text>
       <xsl:text>"</xsl:text><xsl:value-of select="MES/@idref"    /><xsl:text>",</xsl:text>
       <xsl:text>"</xsl:text><xsl:value-of select="TITRE"         /><xsl:text>" </xsl:text>
       <xsl:text>) ; </xsl:text>
       <xsl:call-template name="sdl" />
     
     </xsl:template>
     
     <!-- ########################################################################### -->
     
     </xsl:stylesheet>
     

Le fichier MySql produit est alors : remplit_fa.mysql obtenu par l'application de la transformation fa.xsl au fichier films2.xml, soit films2fa sur le serveur, ou encore : films2+fa.

 

14. Questions diverses

Quelles sont les différences entre XSLT 1 et XSLT 2 ?

Solution :  

XSLT 1 a certaines lacunes que XSLT 2 essaie de combler. En particulier XSL2 utilise XPATH 2. Il faut donc se préoccuper aussi des différences entre XPATH 1 et XPATH 2.

Comme XSL 1 et XSL 2, XPATH... font partie de la Extensible Stylesheet Language Family c'est au W3C/XSL qu'il faut aller pour voir les spécifications correspondantes :

On peut lire XSLT-2-0-in-NET comme exemple concret de nouveauté XSL 2. Pour plus de détails, il est possible de se reporter aux deux articles What's New in XPath 2.0 d'Evan LENZ. et What's New in XSLT 2.0

La longue page sur les opérateurs communs de XQUERY 1 et XPATH 2 est ici.

 

Archive des données, programmes et scripts.

 

Code-source php de cette page ; code javascript utilisé. Retour à la page principale du cours.

 

 

retour gH    Retour à la page principale de   (gH)