Valid XHTML     Valid CSS2    

XML en L2, université d'Angers

    gilles.hunault@univ-angers.fr

 

T.P. numéro 2

 

Table des matières cliquable

  1. Compter des éléments ou des attributs dans un document XML

  2. Expressions XPATH

  3. Une transformation XSL élémentaire

  4. Une deuxième transformation XSL

  5. Transformations XSL avancées

 

Il est possible d'afficher toutes les solutions via  ?solutions=1  et de les masquer via  ?solutions=0 .

1. Compter des éléments ou des attributs dans un document XML

On s'intéresse au fichier leadb880.xml suivant :

Après avoir décrit la structure du fichier, compter le nombre de lignes, le nombre de lignes vides, d'élements et d'attributs. On pourra utiliser tout outil logiciel. Comment trouver le nombre d'élements distincts ?

Solution :  

On peut facilement obtenir le nombre de lignes avec la commande système nommée wc. Pour le nombre de lignes vides, chainer grep et wc est sans doute un bon choix. Pour le nombre d'élements distincts et la structure, xmlstarlet et trang sont des outils biens adaptés. Enfin, pour le nombre d'éléments en tout, on peut chainer xmlstarlet et wc alors que pour le nombre d'attributs en tout, il faut chainer xmlstarlet, grep et wc alors que Voici le détail des commandes associées :


     wc -l leadb880.xml                                # nombre de lignes (6163)
     grep "^$" leadb880.xml         | wc -l            # nombre de lignes vides (881)
     xmlstarlet el leadb880.xml     | wc -l            # nombre d'éléments (3521)
     xmlstarlet el -u leadb880.xml  | wc -l            # nombre d'éléments distincts (5)
     xmlstarlet el -a leadb880.xml  | grep "@" | wc -l # nombre d'attributs (880)
     

Une grammaire raisonnable pour ces données est fournie par le fichier suivant nommé leadb.dtd.

Grammaire leadb.dtd :


     <?xml encoding="UTF-8"?>
     
     <!ELEMENT proteins  (protein)+               >
     <!ELEMENT protein   (accession,class,fasta)  >
     <!ELEMENT accession (#PCDATA)                >
     <!ELEMENT class     (#PCDATA)                >
     <!ELEMENT fasta     (#PCDATA)                >
     
     <!ATTLIST fasta      xmlns CDATA #FIXED ''   length CDATA #REQUIRED>
     

Avec la commande xmlstarlet el -u on dispose de la structure des données  :


     xmlstarlet el -u leadb880.xml
     
     proteins
     proteins/protein
     proteins/protein/accession
     proteins/protein/class
     proteins/protein/fasta
     

 

2. Expressions XPATH

On s'intéresse ici au document films2.xml qui contient des films et des artistes. En voici la grammaire DTD :


     <!ELEMENT FILMSETARTISTES (FILMS,ARTISTES)>
     
     <!ELEMENT FILMS    (FILM)+>
     <!ELEMENT FILM     (TITRE,GENRE,PAYS,MES,ROLES,RESUME?)   >
     <!ELEMENT TITRE    (#PCDATA)                              >
     <!ELEMENT GENRE    (#PCDATA)                              >
     <!ELEMENT PAYS     (#PCDATA)                              >
     <!ELEMENT MES                                      EMPTY  >
     <!ELEMENT ROLES    (ROLE)*                                >
     <!ELEMENT RESUME   (#PCDATA)                              >
     
     <!ELEMENT ROLE     (PRENOM,NOM,INTITULE) >
     <!ELEMENT PRENOM   (#PCDATA)             >
     <!ELEMENT INTITULE (#PCDATA)             >
     <!ELEMENT NOM      (#PCDATA)             >
     
     <!ELEMENT ARTISTES   (ARTISTE)+                      >
     <!ELEMENT ARTISTE    (ARTNOM,ARTPRENOM,ANNEENAISS?)  >
     <!ELEMENT ARTNOM     (#PCDATA)                       >
     <!ELEMENT ARTPRENOM  (#PCDATA)                       >
     <!ELEMENT ANNEENAISS (#PCDATA)                       >
     
     <!ATTLIST ARTISTE xmlns CDATA #FIXED ''   id    CDATA #REQUIRED >
     <!ATTLIST FILM    xmlns CDATA #FIXED ''   Annee CDATA #REQUIRED >
     <!ATTLIST MES     xmlns CDATA #FIXED ''   idref CDATA #REQUIRED >
     

On fournit aussi la structure explicite du fichier (éléments seulement) obtenue à l'aide de la commande xmlstarlet el -u films2.xml :


     FILMSETARTISTES
     FILMSETARTISTES/ARTISTES
     FILMSETARTISTES/ARTISTES/ARTISTE
     FILMSETARTISTES/ARTISTES/ARTISTE/ANNEENAISS
     FILMSETARTISTES/ARTISTES/ARTISTE/ARTNOM
     FILMSETARTISTES/ARTISTES/ARTISTE/ARTPRENOM
     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
     

A l'aide de xmllint en mode «shell», essayer de répondre aux questions suivantes :

  • Quels sont tous les titres de films ?

  • Quel est le titre du neuvième film ?

  • En quelle année est sorti le film Blade Runner ?

  • Quel en est le metteur en scène ?

Solution :  

Voici les instructions à exécuter pour répondre aux questions :


     # lancer xmllint en mode shell sur le fichier des films
     
     xmllint --shell films2.xml
     
     # tous les titres de films
     
     ls //TITRE
     
     # le titre du neuvième film (on trouve Gladiator)
     # on aurait pu écrire en ligne de commandes
     #   grep TITRE films2.xml | head -n 9 | tail -n 1
     
     ls //FILM[position()=9]/TITRE # plus "propre" que ls //FILM[9]/TITRE
     
     # année de sortie du film Blade Runner (1982)
     ls //FILM[TITRE="Blade Runner"]/@Annee
     
     ## metteur en scène du film Blade Runner (Ridley SCOTT)
     
     # solution 1, en deux temps : numéro du metteur en scène (4)
     
     ls //FILM[TITRE="Blade Runner"]//MES/@idref
     
     # artiste associé
     
     ls //ARTISTE[@id="4"]/ARTNOM      # Scott
     ls //ARTISTE[@id="4"]/ARTPRENOM   # Ridley
     
     # solution 2, tout en une seule fois
     
     ls //ARTISTE[@id=//FILM[TITRE="Blade Runner"]//MES/@idref]/ARTNOM
     
     

 

3. Une transformation XSL élémentaire

On voudrait compter le nombre de protéines du fichier leadb880.xml et vérifier que chaque protéine a bien un attribut length. Trouver une solution en ligne de commandes puis à l'aide d'une transformation XSL. Comment peut-on trouver la plus petite longueur de protéine et la plus grande ?

Solution :  

Une protéine correspond à un élément protein donc il suffit de compter les chaines <protein> pour les dénombrer. L'attribut length, lui, peut se repérer grâce à l'expression <fasta length=. Dans les deux cas, on trouve 880 lignes correspondantes, mais cela ne prouve sans doute pas que chaque protéine a bien un attribut length dans un sous-élément fasta sauf à valider le fichier pour la grammaire de la question 1. Par contre rechercher toutes les expressions proteins/protein/fasta/@length dans la sortie de xmlstarlet el -a peut le prouver. Voici les commandes à utiliser :


     grep "<protein>" leadb880.xml      | wc -l      # 880 protéines
     grep "<fasta length=" leadb880.xml | wc -l      # 880 longueurs
     xmlstarlet el -a leadb880.xml      | grep "proteins/protein/fasta/@length" | wc -l  # 880 longueurs
     

Pour effectuer une transformation XSL qui réalise les mêmes comptages, il suffit de mettre une seule règle sur la racine du document et d'utiliser la fonction XPATH nommée count().

Transformation proteines.xsl :


     <?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" />
     
     <xsl:template match="/">
     
     Il y a <xsl:value-of select="count(//protein)" /> protéines
     et <xsl:value-of select="count(//protein/fasta/@length)" /> longueurs.
     
     </xsl:template>
     
     </xsl:stylesheet>
     

Pour exécuter cette transformation, on peut utiliser xsltproc :


     $gh> xsltproc proteines.xsl leadb880.xml
     
     Il y a 880 protéines
     et 880 longueurs.
     

mais ce n'est pas le seul choix possible. Par exemple on peut utiliser xmlstarlet :


     $gh> xmlstarlet tr proteines.xsl leadb880.xml
     
     Il y a 880 protéines
     et 880 longueurs.
     

On peut aussi mettre l'appel du fichier XSL dans l'en-tête du fichier XML et faire exécuter la transformation par le navigateur, comme ici.

Pour trouver la longueur minimale et la longueur maximale ???

 

4. Une deuxième transformation XSL

Dans le document films2.xml, combien y a-t-il de films ? Et d'artistes ? Combien de références pour combien de metteurs en scène ? On écrira une transformation XSL qui affichera ces résultats en mode texte qu'on exécutera avec xmlstarlet avant de modifier le document pour avoir un rendu dans une page Web.

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 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 nbfa1.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>
     

     $gh> xmlstarlet tr nbfa1.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.
     

Produire une page Web résultat est un peu plus compliqué car ???

 

5. Transformations XSL avancées

On voudrait effectuer des calculs statistiques et tracer des graphiques pour étudier la longueur des protéines du fichier leadb880.xml. Que peut-on calculer et tracer via XSL ?

Solution :  

XSL ne peut pas grand chose pour nous ici car XSL est conçu pour transformer du texte, pas pour calculer. Par contre XSL peut nous aider à produire un fichier CSV utilisable par Excel, le logiciel R ou tout autre logiciel statistique. Pour cela, il suffit d'exporter le nom de chaque protéine, sa classe et sa longueur. C'est ce que fait la transformation suivante :

 fichier prot_export.xsl non vu

On pourra vérifier que le fichier obtenu, soit prot_export.csv est utilisable par Microsoft Office Excel ou par Libre Office Calc :

 fichier prot_export.csv non vu

 

 

Code-source php de cette page.

 

 

retour gH    Retour à la page principale de   (gH)