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
7. Transformations entre éléments et attributs
8. Ajouts et modifications d'éléments ou d'attributs
10. Suppression de la mise en forme XHTML
11. Tris avec XSL
12. Fichiers inclus, sous-programmes et variables en XSL
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 : masquer la 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/TITRELa 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#A9mentNOM, 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/LarryPour 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 : masquer la 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 BessonDans 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 : masquer la 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 / > byeLa 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 :
Et leurs résultats :
> exsl AAA18335.xml ncbi_gi_1.xsl gb|AAA18335.1| gi|424143 > exsl AAA18335.xml ncbi_gi_2.xsl 424143Remarque : 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 : masquer la 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 : masquer la 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 : masquer la 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 : masquer la 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 : masquer la 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 : masquer la 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 : masquer la 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 : masquer la 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 : masquer la 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="'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'" disable-output-escaping="yes" /> <xsl:call-template name="sdl" /> <xsl:value-of select="'<html xmlns="http://www.w3.org/1999/xhtml" lang="fr" xml:lang="fr">'" 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="'<body class="beige_jpg">'" disable-output-escaping="yes" /> <xsl:call-template name="sdl" /> <xsl:value-of select="'<blockquote>'" 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="'</blockquote>'" disable-output-escaping="yes" /> <xsl:call-template name="sdl" /> <xsl:value-of select="'</body>'" disable-output-escaping="yes" /> <xsl:call-template name="sdl" /> <xsl:value-of select="'</html>'" disable-output-escaping="yes" /> <xsl:call-template name="sdl" /> </xsl:template> <!-- ########################################################################### --> <!-- début de section --> <!-- ########################################################################### --> <xsl:template name="debutSection"> <xsl:value-of select="'<table cellpadding="50" class="bgcolor_white" width="90%" summary="cadre général"><tr><td class="bgcolor_white">'" disable-output-escaping="yes" /> <xsl:call-template name="sdl" /> </xsl:template> <!-- ########################################################################### --> <!-- fin de section --> <xsl:template name="finSection"> <xsl:value-of select="'</td></tr></table>'" disable-output-escaping="yes" /> <xsl:call-template name="sdl" /> </xsl:template> <!-- ########################################################################### --> <!-- début de tableau XHTML --> <!-- ########################################################################### --> <xsl:template name="debutTableau"> <xsl:value-of select="'<table border="1" class="bgcolor_white collapse" cellpadding="20" cellspacing="5">'" disable-output-escaping="yes" /> <xsl:call-template name="sdl" /> </xsl:template> <!-- ########################################################################### --> <!-- fin de tableau XHTML --> <!-- ########################################################################### --> <xsl:template name="finTableau"> <xsl:value-of select="'</table>'" 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 : masquer la 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 : masquer la 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 à la page principale de (gH)