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 2 : vérification et validation XML

                     gilles.hunault "at" univ-angers.fr

 

Table des matières cliquable

  1. Ecriture de grammaires élémentaires

  2. Grammaires moins élémentaires

  3. Lecture de grammaires courantes de petite taille

  4. Lecture de grammaires courantes de grande taille

  5. Conversions entres grammaires DTD et XSD ; vérification de grammaires

  6. Contraintes et facettes dans les schémas XSD

  7. Autres grammaires dont Relax NG ; espaces de noms

  8. Questions diverses

 

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

 

1. Ecriture de grammaires élémentaires

Ecrire des grammaires DTD élémentaires associées aux fichiers serv00.xml, serv01.xml... serv05.xml de la série 1 d'exercices. On nommera serv00.dtd, serv01.dtd... serv05.dtd les fichiers-grammaires correspondants. Ecrire ensuite les grammaires élémentaires XSD associées.

Ecrire les grammaires DTD élémentaires associées aux fichiers pers01.xml, pers02.xml... pers04.xml de la série 1 d'exercices. On nommera pers01.dtd, pers02.dtd... pers04.dtd les fichiers-grammaires correspondants. Ecrire ensuite les grammaires XSD associées.

Peut-on imposer que les dates de naissance sont des entiers positifs supérieurs à 1870 ?

Idem avec les fichiers fasta01.xml à fasta05.xml puis pour agences03.xml et agences04.xml. Peut-on faire un include des grammaires services et personnes pour créer une grammaire agences ?

Remarque : après avoir écrit «à la main» les grammaires, on pourra essayer de trouver un générateur de tels fichiers au vu d'un fichier XML type.

Solution :  

1.1 Grammaires pour les services

La première série de grammaires DTD est facile à construire puisqu'on a peu de niveaux dans la hiérarchie. Une fois qu'on a compris qu'un élément se déclare par <!ELEMENT ...> et que pour déclarer que Y est un attribut de X, il faut écrire <!ATTLIST X Y...>, le plus dur est fait pour les DTD. Comme l'énoncé ne précise aucune contrainte particulière, nous avons choisi la solution minimale : nous avons considéré que services ne pouvait pas être vide, que nomDeService et numService sont simplement des chaines de caractères obligatoires en tant qu'attribut, d'où le contenu (#PCDATA) pour les éléments et CDATA #REQUIRED pour les attributs.

Seule la grammaire serv03.dtd mérite un peu plus d'attention car la présence de retour-charriot dans serv03.xml empêche la définition en type EMPTY pour service.

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

serv00.dtd       serv01.dtd       serv02.dtd       serv03.dtd       serv04.dtd       serv05.dtd       

serv00.xsd       serv01.xsd       serv02.xsd       serv03.xsd       serv04.xsd       serv05.xsd       

Pour les grammaires XSD, il y a le choix de définir directement les éléments dans la hiérarchie, comme pour serv00.xsd ou de définir des références aux éléments puis de définir les éléments, comme pour serv01.xsd. Ainsi, au lieu de serv05.xsd, nous aurions pu définir serv05autre.xsd. Après réflexion, il nous semble que l'approche par référence est plus modulaire. Ce sera donc celle que nous allons privilégier dans la suite des exercices.

1.2 Grammaires pour les personnes

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

pers01.dtd       pers02.dtd       pers03.dtd       pers04.dtd       

pers01.xsd       pers02.xsd       pers03.xsd       pers04.xsd       

1.3 Grammaires pour les séquences Fasta

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

fasta01.dtd       fasta02.dtd       fasta03.dtd       fasta04.dtd       fasta05.dtd       

fasta01.xsd       fasta02.xsd       fasta03.xsd       fasta04.xsd       fasta05.xsd       

1.4 Grammaires pour les agences

agences03dtd.xml       agences04dtd.xml       agences05dtd.xml       

agences03.dtd       agences04.dtd       agences05.dtd       

agences03.xsd       agences04.xsd       agences05.xsd       

Comme le montre la grammaire agences05.dtd, il est possible de réaliser des include pour une DTD à l'aide des entités paramétriques qu'on utilise avec %, à ne pas confondre avec une entité classique qui s'utilise avec &. XSD fournit des mécanismes plus complets avec xs:include et xs:import mais plus difficiles à mettre en oeuvre à cause des espaces des noms.

1.5 A propos de la génération automatique de grammaires

Une fois la syntaxe des fichiers DTD et XSD maitrisée, un outil comme trang permet d'automatiser la génération de grammaires à partir d'un ou plusieurs fichiers XML. Voici, avec la forme longue puis avec la forme courte, comment générer respectivement une grammaire DTD puis une grammaire XSD pour le fichier serv00.xml :


     # génération de grammaire DTD à partir de fichier(s) XML via trang, forme longue
     
     java -jar $trangPath trang.jar -I xml -O dtd -i encoding=ISO8859-15 serv00.xml services.dtd
     
     # génération de grammaire XSD à partir de fichier(s) XML via trang, forme courte
     
     trang serv00.xml services.xsd
     

Voici les grammaires produites :


     <?xml encoding="UTF-8"?>
     
     <!ELEMENT services (service)+>
     <!ATTLIST services
       xmlns CDATA #FIXED ''>
     
     <!ELEMENT service (#PCDATA)>
     <!ATTLIST service
       xmlns CDATA #FIXED ''>
     

     <?xml version="1.0" encoding="UTF-8"?>
     <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
       <xs:element name="services">
         <xs:complexType>
           <xs:sequence>
             <xs:element maxOccurs="unbounded" ref="service"/>
           </xs:sequence>
         </xs:complexType>
       </xs:element>
       <xs:element name="service" type="xs:NCName"/>
     </xs:schema>
     

Attention quand même à relire les grammaires générées car il peut y avoir des surprises !

 

2. Grammaires moins élémentaires

Ecrire les grammaires DTD et XSD associées au fichier dessin.xml de la série 1 d'exercices. On nommera dessin.dtd et dessin.xsd les fichiers-grammaires correspondants. On essaiera de paramétrer l'attribut couleur qui est commun.

Ecrire un fichier minimal ouimaisnon.xml qui est valide pour la grammaire g1.dtd mais non valide pour la grammaire g2.dtd. Fournir ensuite un fichier livre.xml valide pour g2.dtd.

Ecrire une grammaire pour le fichier films2 en DTD puis en XSD. Pourquoi ne peut-on pas parler de la grammaire DTD d'un fichier ?

Solution :  

2.1 Solution pour dessin.xml

Là encore, pour dessin.xml, il y a peu d'éléments et d'attributs dans dessin.xml donc une grammaire DTD «vite fait» peut être dessin.dtd dont le contenu est :


     <!-- dessin.dtd -->
     
     <!-- une grammaire élémentaire pour dessin.xml -->
     
     <!ELEMENT dessins   (dessin+)  >
     <!ELEMENT dessin    (cercle|rectangle|triangle)* >
     <!ELEMENT cercle    EMPTY >
     <!ELEMENT rectangle EMPTY>
     <!ELEMENT triangle  EMPTY>
     
     <!ATTLIST dessins largeur CDATA "REQUIRED">
     <!ATTLIST dessins hauteur CDATA "REQUIRED">
     
     <!ATTLIST cercle xcentre CDATA "REQUIRED">
     <!ATTLIST cercle ycentre CDATA "REQUIRED">
     <!ATTLIST cercle rayon   CDATA "REQUIRED">
     <!ATTLIST cercle couleur CDATA "REQUIRED">
     
     <!ATTLIST rectangle xcsg    CDATA "REQUIRED">
     <!ATTLIST rectangle ycsg    CDATA "REQUIRED">
     <!ATTLIST rectangle largeur CDATA "REQUIRED">
     <!ATTLIST rectangle hauteur CDATA "REQUIRED">
     <!ATTLIST rectangle couleur CDATA "REQUIRED">
     
     <!ATTLIST triangle couleur CDATA "REQUIRED">
     <!ATTLIST triangle xpoint1 CDATA "REQUIRED">
     <!ATTLIST triangle ypoint1 CDATA "REQUIRED">
     <!ATTLIST triangle xpoint2 CDATA "REQUIRED">
     <!ATTLIST triangle ypoint2 CDATA "REQUIRED">
     <!ATTLIST triangle xpoint3 CDATA "REQUIRED">
     <!ATTLIST triangle ypoint3 CDATA "REQUIRED">
     

Pour forcer les couleurs à ne prendre que les valeurs autorisées, on peut utiliser une liste de valeurs, soit :


     <!-- dessin2.dtd -->
     
     <!-- une autre grammaire pour dessin.xml -->
     
     <!ELEMENT dessins   (dessin+)  >
     <!ELEMENT dessin    (cercle|rectangle|triangle)* >
     <!ELEMENT cercle    EMPTY >
     <!ELEMENT rectangle EMPTY>
     <!ELEMENT triangle  EMPTY>
     
     <!ATTLIST dessins largeur CDATA "REQUIRED">
     <!ATTLIST dessins hauteur CDATA "REQUIRED">
     
     <!ATTLIST cercle couleur (bleu|jaune|rouge|vert) "bleu" >
     <!ATTLIST cercle xcentre CDATA "REQUIRED">
     <!ATTLIST cercle ycentre CDATA "REQUIRED">
     <!ATTLIST cercle rayon   CDATA "REQUIRED">
     
     <!ATTLIST rectangle couleur (bleu|jaune|rouge|vert) "bleu" >
     <!ATTLIST rectangle xcsg    CDATA "REQUIRED">
     <!ATTLIST rectangle ycsg    CDATA "REQUIRED">
     <!ATTLIST rectangle largeur CDATA "REQUIRED">
     <!ATTLIST rectangle hauteur CDATA "REQUIRED">
     
     <!ATTLIST triangle couleur (bleu|jaune|rouge|vert) "bleu" >
     <!ATTLIST triangle xpoint1 CDATA "REQUIRED">
     <!ATTLIST triangle ypoint1 CDATA "REQUIRED">
     <!ATTLIST triangle xpoint2 CDATA "REQUIRED">
     <!ATTLIST triangle ypoint2 CDATA "REQUIRED">
     <!ATTLIST triangle xpoint3 CDATA "REQUIRED">
     <!ATTLIST triangle ypoint3 CDATA "REQUIRED">
     

Pour éviter la duplication par copier/coller de cette liste des couleurs, le mieux est d'utiliser une entité paramétrique, qui fonctionne comme une entité HTML mais qui commence par le symbole % (pourcent) :


     <!-- dessin3.dtd -->
     
     <!-- encore une autre grammaire pour dessin.xml -->
     
     <!ENTITY % couleur "(bleu|jaune|rouge|vert)" >
     
     <!ELEMENT dessins   (dessin+)  >
     <!ELEMENT dessin    (cercle|rectangle|triangle)* >
     <!ELEMENT cercle    EMPTY >
     <!ELEMENT rectangle EMPTY>
     <!ELEMENT triangle  EMPTY>
     
     <!ATTLIST dessins largeur CDATA "REQUIRED">
     <!ATTLIST dessins hauteur CDATA "REQUIRED">
     
     <!ATTLIST cercle couleur %couleur;  "bleu" >
     <!ATTLIST cercle xcentre CDATA "REQUIRED">
     <!ATTLIST cercle ycentre CDATA "REQUIRED">
     <!ATTLIST cercle rayon   CDATA "REQUIRED">
     
     <!ATTLIST rectangle couleur %couleur; "bleu" >
     <!ATTLIST rectangle xcsg    CDATA "REQUIRED">
     <!ATTLIST rectangle ycsg    CDATA "REQUIRED">
     <!ATTLIST rectangle largeur CDATA "REQUIRED">
     <!ATTLIST rectangle hauteur CDATA "REQUIRED">
     
     <!ATTLIST triangle couleur %couleur; "bleu" >
     <!ATTLIST triangle xpoint1 CDATA "REQUIRED">
     <!ATTLIST triangle ypoint1 CDATA "REQUIRED">
     <!ATTLIST triangle xpoint2 CDATA "REQUIRED">
     <!ATTLIST triangle ypoint2 CDATA "REQUIRED">
     <!ATTLIST triangle xpoint3 CDATA "REQUIRED">
     <!ATTLIST triangle ypoint3 CDATA "REQUIRED">
     

On peut aller encore plus loin et intégrer la couleur par défaut dans l'entité ou décider qu'il est plus modulaire de définir une autre entité pour la couleur par défaut 


     <!-- une entité pour la liste des couleurs et la couleur par défaut   -->
     <!-- avec un exemple d'utilisation                                    -->
     
     <!ENTITY  % couleur "(bleu|jaune|rouge|vert) 'bleu' "                   >
     ...
     <!ATTLIST   cercle  couleur %couleur;                                   >
     
     <!-- une entité pour la liste des couleurs et une autre entité pour la couleur par défaut -->
     <!-- avec un exemple d'utilisation                                                        -->
     
     <!ENTITY % couleur     "(bleu|jaune|rouge|vert)"                                            >
     <!ENTITY % couleur_def "'bleu'"                                                             >
     ...
     <!ATTLIST  cercle      couleur %couleur;  %couleur_def;                                     >
     
     

Voici donc les 5 grammaires DTD possibes et leur traduction automatique en schéma XSD :

dessin1.dtd       dessin2.dtd       dessin3.dtd       dessin4.dtd       dessin5.dtd       

dessin1.xsd       dessin2.xsd       dessin3.xsd       dessin4.xsd       dessin5.xsd       

2.2 Solution pour les grammaires g1.dtd et g2.dtd

Il ne faut pas se laisser impressionner par la longueur de la grammaire g1.dtd car de nombreux de ses éléments sont facultatifs :


     <!-- g1.dtd  -->
     
     <!ELEMENT livre (preface?,introduction?,chapitres*,conclusion?,annexes?,references,infosPublications) >
     <!ELEMENT preface       (#PCDATA)           >
     <!ELEMENT introduction  (#PCDATA)           >
     <!ELEMENT chapitres     (#PCDATA|chapitre)* >
     <!ELEMENT chapitre      (section*)          >
     <!ELEMENT section       (#PCDATA)           >
     <!ELEMENT conclusion    (#PCDATA)           >
     <!ELEMENT annexes       (#PCDATA)           >
     <!ELEMENT autre         (#PCDATA)           >
     <!ELEMENT suite         (#PCDATA)           >
     <!ELEMENT references        ANY             >
     <!ELEMENT infosPublications EMPTY           >
     

Donc si on se focalise sur les éléments obligatoires, on peut se limiter à un fichier ouimaisnon.xml comme celui-ci :


     <?xml version="1.0" ?>
     <!-- ouimaisnon.xml -->
     
     <livre>
     <references>
     pomme
     <autre>
     poire
     </autre>
     scoubidou
     <suite />
     fin
     </references>
     <infosPublications />
     </livre>
     

On notera au passage ce que permet le mot clé ANY pour l'élément references, qui, s'il permet de tester des documents en cours de rédaction, n'est pas très contraignant. De même en ce qui concerne (#PCDATA|chapitre)* pour l'élément chapitres. Pour vérifier que ce fichier est valide pour g1 mais non pour g2, le plus simple est d'utiliser xmlstarlet ou xmllint car on n'a pas besoin d'écrire explicitement <!DOCTYPE avant l'élément racine, ce que ne permet pas rxp :


     $gh>  rxp -s -v ouimaisnon.xml # n'affiche rien, donc ceci prouve que le fichier est bien formé
     
     RXP 1.5.0 Copyright Richard Tobin, LTG, HCRC, University of Edinburgh
     Input encoding UTF-8, output encoding UTF-8
     
     $gh>  rxp -s -V ouimaisnon.xml
     
     Warning: Document has no DTD, validating abandoned
     (detected at end of prolog of document file:///home/gh/public_html/Webrd/ouimaisnon.xml)
     
     $gh>  xmlstarlet val -d g1.dtd ouimaisnon.xml
     
     ouimaisnon.xml - valid
     
     $gh>  xmlstarlet val -d g2.dtd ouimaisnon.xml
     
     ouimaisnon.xml - invalid
     
     $gh>  xmlstarlet val -e -d g2.dtd ouimaisnon.xml # il faut utiliser l'option -e pour voir le détail des erreurs
     
     ouimaisnon.xml:4.0: Element livre content does not follow the DTD,
     expecting (preface? , introduction? , partie+ , conclusion? , annexes? , references , infosPublications),
     got (references infosPublications )
     ouimaisnon.xml:5.0: Element references was declared EMPTY this one has content
     ouimaisnon.xml:5.0: Element references does not carry attribute motclef
     ouimaisnon.xml:5.0: Element references does not carry attribute txtref
     ouimaisnon.xml:7.0: No declaration for element autre
     ouimaisnon.xml:11.0: No declaration for element suite
     ouimaisnon.xml:14.0: Element infosPublications does not carry attribute nref
     ouimaisnon.xml - invalid
     
     $gh>  xmllint --noout --dtdvalid g1.dtd ouimaisnon.xml # n'affiche rien car valide pour g1
     
     $gh>  xmllint --noout --dtdvalid g2.dtd ouimaisnon.xml
     
     ouimaisnon.xml:4: element livre: validity error : Element livre content does not follow the DTD,
     expecting (preface? , introduction? , partie+ , conclusion? , annexes? , references , infosPublications),
     got (references infosPublications )
     ouimaisnon.xml:5: element references: validity error : Element references was declared EMPTY this one has content
     ouimaisnon.xml:5: element references: validity error : Element references does not carry attribute motclef
     ouimaisnon.xml:5: element references: validity error : Element references does not carry attribute txtref
     ouimaisnon.xml:7: element autre: validity error : No declaration for element autre
     ouimaisnon.xml:11: element suite: validity error : No declaration for element suite
     ouimaisnon.xml:14: element infosPublications: validity error : Element infosPublications does not carry attribute nref
     Document ouimaisnon.xml does not validate against g2.dtd
     
     $gh>  xmllint --noout --dtdvalid g2.dtd livre.xml # n'affiche rien car valide pour g2
     
     $gh>  xmlstarlet val -d g2.dtd livre.xml
     
     livre.xml - valid
     
     

Par contre, la grammaire g2.dtd est plus exigeante que la grammaire g1.dtd :


     <!-- g2.dtd  -->
     
     <!ELEMENT livre (preface?,introduction?,partie+,conclusion?,annexes?,references,infosPublications) >
     <!ELEMENT preface           (#PCDATA)          >
     <!ELEMENT introduction      (#PCDATA)          >
     <!ELEMENT partie            (chapitre+)        >
     <!ELEMENT chapitre          (#PCDATA|section)* >
     <!ELEMENT section           (#PCDATA)          >
     <!ELEMENT conclusion        (#PCDATA)          >
     <!ELEMENT annexes           (#PCDATA)          >
     <!ELEMENT references        EMPTY              >
     <!ELEMENT infosPublications EMPTY              >
     
     <!ATTLIST partie        numpart ID       #IMPLIED   >
     <!ATTLIST chapitre      numchap ID       #REQUIRED  >
     <!ATTLIST section       numsec  ID       "REQUIRED" >
     <!ATTLIST references    numref  ID       #IMPLIED   >
     <!ATTLIST references    txtref  CDATA    #REQUIRED  >
     <!ATTLIST references    motclef NMTOKEN  #REQUIRED  >
     <!ATTLIST infosPublications nref IDREF   #REQUIRED  >
     <!ATTLIST infosPublications date CDATA   "?"        >
     

Donc un fichier livre.xml valide pour g2 est un peu plus technique et demande un peu plus de réflexion :


     <?xml version="1.0" encoding="ISO-8859-15" ?>
     <!-- livre.xml -->
     
     <livre>
     
     <preface>
     Ceci est la préface.
     </preface>
     
     <introduction>
     Ceci est l'introduction.
     </introduction>
     
     <partie numpart="partie1">
     <chapitre numchap="chap1.1">
     Ceci est le chapitre 1 de la partie 1.
     </chapitre>
     <chapitre numchap="chap1.2">
     Ceci est le chapitre 2 de la partie 1.
     </chapitre>
     </partie>
     
     <partie>
     <!-- partie 2 mais sans numpart explicite -->
     <chapitre numchap="chap2.1">
     Ceci est le chapitre 1 de la partie 2.
     <section numsec="sec2.1.1">
     ceci est etc.
     </section>
     <section numsec="sec2.1.2">
     ceci est etc.
     </section>
     </chapitre>
     </partie>
     
     <partie numpart="partie3">
     <chapitre numchap="chap3.1">
     Ceci est le chapitre 1 de la partie 3.
     </chapitre>
     </partie>
     
     <conclusion>
     Ceci est la conclusion.
     </conclusion>
     
     <references numref="ref1" txtref="standard" motclef="demo" />
     
     <infosPublications nref="ref1" />
     
     </livre>
     

Afin de vous entrainer à la lecture synoptique et comparative de DTD et XSD, voici donc les 2 grammaires DTD possibes et leur traduction automatique en schéma XSD :

g1.dtd       g2.dtd       g1.xsd       g2.xsd       

2.3 Solution pour le fichier films2.xml

La grammaire pour films2.xml est un peu compliquée à écrire. D'abord parce qu'il y a une hiérarchie un peu moins évidente. Ensuite, parce que certains éléments ne sont pas renseignés, ce qui n'est pas très facile à détecter car les éléments absents ne le sont pas en début de fichier : certains films n'ont pas d'élément GENRE et certains films n'ont pas d'élément RESUME, certains artistes n'ont pas d'élément ANNEENAISS.

On pourrait éventuellement avoir une idée de la concomittance entre éléments et attributs à l'aide notre programme eltatt si on l'applique à films2.xml soit le résultat suivant.

On peut donc écrire la grammaire minimale suivante qui autorise à n'avoir aucun film ni aucun artiste :


     <!-- films2.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      (#PCDATA)                              >
     <!ELEMENT ROLES    (ROLE*)                                >
     <!ELEMENT ROLE     (PRENOM,NOM,INTITULE)                  >
     <!ELEMENT PRENOM   (#PCDATA)                              >
     <!ELEMENT NOM      (#PCDATA)                              >
     <!ELEMENT INTITULE (#PCDATA)                              >
     <!ELEMENT RESUME   (#PCDATA)                              >
     <!ATTLIST FILM     Annee   CDATA #REQUIRED                >
     <!ATTLIST MES      idref   CDATA #REQUIRED                >
     
     <!ELEMENT ARTISTES   (ARTISTE*)                           >
     <!ELEMENT ARTISTE    (ACTNOM,ACTPNOM,ANNEENAISS?)         >
     <!ELEMENT ACTNOM     (#PCDATA)                            >
     <!ELEMENT ACTPNOM    (#PCDATA)                            >
     <!ELEMENT ANNEENAISS (#PCDATA)                            >
     <!ATTLIST ARTISTE    id  CDATA #REQUIRED                  >
     

Il n'est pas possible de profiter directement des déclarations ID et IDREF des DTD car dans la norme XML un identifiant ou une référence à un identifiant ne peut pas être uniquement numérique (de façon plus précise, il ne doit pas commencer par un chiffre). Or, c'est souvent le cas lorsque l'attribut provient d'un champ autoincrémenté d'une base de données. Voici ce qui se passe si on essaie de valider :


     @ghchu~/public_html/Webrd|(~gH) > xmlstarlet val -d films2.dtd films2dtd.xml
     films2dtd.xml - valid
     
     @ghchu~/public_html/Webrd|(~gH) > xmlstarlet val -d films3.dtd films2dtd.xml  | head
     films2dtd.xml:7: element MES: validity error : Syntax of value for attribute idref of MES is not valid
     films2dtd.xml:19: element MES: validity error : Syntax of value for attribute idref of MES is not valid
     films2dtd.xml:29: element MES: validity error : Syntax of value for attribute idref of MES is not valid
     films2dtd.xml:41: element MES: validity error : Syntax of value for attribute idref of MES is not valid
     ...
     films2dtd.xml:591: element ARTISTE: validity error : Syntax of value for attribute id of ARTISTE is not valid
     films2dtd.xml:592: element ARTISTE: validity error : Syntax of value for attribute id of ARTISTE is not valid
     films2dtd.xml:593: element ARTISTE: validity error : Syntax of value for attribute id of ARTISTE is not valid
     films2dtd.xml:594: element ARTISTE: validity error : Syntax of value for attribute id of ARTISTE is not valid
     films2dtd.xml:595: element ARTISTE: validity error : Syntax of value for attribute id of ARTISTE is not valid
     films2dtd.xml:596: element ARTISTE: validity error : Syntax of value for attribute id of ARTISTE is not valid
     ...
     
     @ghchu~/public_html/Webrd|(~gH) > xmlstarlet val -s films2.xsd films2.xml
     films2.xml - valid
     
     @ghchu~/public_html/Webrd|(~gH) > xmlstarlet val -s films3.xsd films2.xml
     films2.xml - invalid
     
     @ghchu~/public_html/Webrd|(~gH) > xmlstarlet val -e -s films3.xsd films2.xml
     films2.xml:6: element MES: Schemas validity error : Element 'MES', attribute 'idref': '3' is not a valid value of the atomic type 'xs:IDREF'.
     films2.xml:18: element MES: Schemas validity error : Element 'MES', attribute 'idref': '4' is not a valid value of the atomic type 'xs:IDREF'.
     films2.xml:28: element MES: Schemas validity error : Element 'MES', attribute 'idref': '6' is not a valid value of the atomic type 'xs:IDREF'.
     films2.xml:40: element MES: Schemas validity error : Element 'MES', attribute 'idref': '9' is not a valid value of the atomic type 'xs:IDREF'.
     films2.xml:46: element MES: Schemas validity error : Element 'MES', attribute 'idref': '10' is not a valid value of the atomic type 'xs:IDREF'.
     films2.xml:58: element MES: Schemas validity error : Element 'MES', attribute 'idref': '13' is not a valid value of the atomic type 'xs:IDREF'.
     ...
     films2.xml:590: element ARTISTE: Schemas validity error : Element 'ARTISTE', attribute 'id': '6' is not a valid value of the atomic type 'xs:ID'.
     films2.xml:590: element ARTNOM: Schemas validity error : Element 'ARTNOM': This element is not expected. Expected is ( ACTNOM ).
     films2.xml:591: element ARTISTE: Schemas validity error : Element 'ARTISTE', attribute 'id': '3' is not a valid value of the atomic type 'xs:ID'.
     films2.xml:591: element ARTNOM: Schemas validity error : Element 'ARTNOM': This element is not expected. Expected is ( ACTNOM ).
     ...
     
     
     

Si on modifie le fichier des films en ajoutant les 3 lettres art devant chaque identifiant et chaque référence d'identifiant, soit :


     # version avec des id et des idrefs numériques
     
     <?xml version="1.0" encoding="ISO-8859-1"?>
     <!-- films3dtd.xml -->
     <!DOCTYPE FILMSETARTISTES SYSTEM "films3.dtd">
     <FILMSETARTISTES>
     <FILMS>
     <FILM Annee='1958'>
     <TITRE>Vertigo</TITRE>
     <GENRE>Drame</GENRE><PAYS>USA</PAYS><MES idref="3"></MES>
     ...
     <ARTISTE id="119"><ACTNOM>Parillaud</ACTNOM><ACTPNOM>Anne</ACTPNOM><ANNEENAISS>1960</ANNEENAISS></ARTISTE>
     <ARTISTE id="120"><ACTNOM>Anglade</ACTNOM><ACTPNOM>Jean-Hughes</ACTPNOM><ANNEENAISS>1955</ANNEENAISS></ARTISTE>
     <ARTISTE id="121"><ACTNOM>Barr</ACTNOM><ACTPNOM>Jean-Marc</ACTPNOM><ANNEENAISS>1960</ANNEENAISS></ARTISTE>
     </ARTISTES>
     </FILMSETARTISTES>
     
     # version avec des id et des idrefs qui commencent par art
     # (seuls ces id et idrefs sont modélisables par ID et IDREF dans une DTD)
     
     <?xml version="1.0" encoding="ISO-8859-1"?>
     <!-- films3dtd.xml -->
     <!DOCTYPE FILMSETARTISTES SYSTEM "films3.dtd">
     <FILMSETARTISTES>
     <FILMS>
     <FILM Annee='1958'>
     <TITRE>Vertigo</TITRE>
     <GENRE>Drame</GENRE><PAYS>USA</PAYS><MES idref="art3"></MES>
     ...
     <ARTISTE id="art119"><ACTNOM>Parillaud</ACTNOM><ACTPNOM>Anne</ACTPNOM><ANNEENAISS>1960</ANNEENAISS></ARTISTE>
     <ARTISTE id="art120"><ACTNOM>Anglade</ACTNOM><ACTPNOM>Jean-Hughes</ACTPNOM><ANNEENAISS>1955</ANNEENAISS></ARTISTE>
     <ARTISTE id="art121"><ACTNOM>Barr</ACTNOM><ACTPNOM>Jean-Marc</ACTPNOM><ANNEENAISS>1960</ANNEENAISS></ARTISTE>
     </ARTISTES>
     </FILMSETARTISTES>
     
     

alors, on peut utiliser ID et IDREF comme suit :


     <!-- films3.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      (#PCDATA)                              >
     <!ELEMENT ROLES    (ROLE*)                                >
     <!ELEMENT ROLE     (PRENOM,NOM,INTITULE)                  >
     <!ELEMENT PRENOM   (#PCDATA)                              >
     <!ELEMENT NOM      (#PCDATA)                              >
     <!ELEMENT INTITULE (#PCDATA)                              >
     <!ELEMENT RESUME   (#PCDATA)                              >
     <!ATTLIST FILM     Annee   CDATA #REQUIRED                >
     <!ATTLIST MES      idref   IDREF #REQUIRED                >
     
     <!ELEMENT ARTISTES   (ARTISTE*)                           >
     <!ELEMENT ARTISTE    (ACTNOM,ACTPNOM,ANNEENAISS?)         >
     <!ELEMENT ACTNOM     (#PCDATA)                            >
     <!ELEMENT ACTPNOM    (#PCDATA)                            >
     <!ELEMENT ANNEENAISS (#PCDATA)                            >
     <!ATTLIST ARTISTE    id  ID #REQUIRED                     >
     

Voici par exemple les messages d'erreur si on oublie de fournir un identifiant, si on définit deux fois le même identifiant ou si on fait référence à un identifiant qui n'existe pas (nous avons mis art3333 au lieu de art3 comme référence pour le premier film) :


     $gh> rxp -s -V films4dtd.xml
     
     Warning: Required attribute idref for element MES is not present
     in unnamed entity at line 20 char 52 of file:///home/gh/public_html/Webrd/films4dtd.xml
     
     Warning: Duplicate ID attribute value art6
     in unnamed entity at line 593 char 19 of file:///home/gh/public_html/Webrd/films4dtd.xml
     
     Warning: The ID art3333 was referred to but never defined
     (detected at end of body of document file:///home/gh/public_html/Webrd/films4dtd.xml)
     
     
     $gh> xmllint --noout --dtdvalid films3.dtd --valid films4dtd.xml
     
     films4dtd.xml:20: element MES: validity error : Element MES does not carry attribute idref
     <GENRE>Science-fiction</GENRE><PAYS>USA</PAYS><MES></MES>
                                                              ^
     films4dtd.xml:593: element ARTISTE: validity error : ID art6 already defined
     <ARTISTE id="art6"><ACTNOM>Cameron</ACTNOM><ACTPNOM>James</ACTPNOM><ANNEENAISS>1
                       ^
     films4dtd.xml:712: element MES: validity error : IDREF attribute idref references an unknown ID "art3333"
     
     ^
     films4dtd.xml:20: element MES: validity error : Element MES does not carry attribute idref
     films4dtd.xml:593: element ARTISTE: validity error : ID art6 already defined
     films4dtd.xml:8: element MES: validity error : IDREF attribute idref references an unknown ID "art3333"
     Document films4dtd.xml does not validate against films3.dtd
     
     $gh> xmlstarlet val -d films3.dtd -e films4dtd.xml
     
     films4dtd.xml:593.12: ID art6 already defined
     <ARTISTE id="art6"><ACTNOM>Cameron</ACTNOM><ACTPNOM>James</ACTPNOM><ANNEENAISS>1
                       ^
     films4dtd.xml:20.0: Element MES does not carry attribute idref
     films4dtd.xml:593.0: ID art6 already defined
     films4dtd.xml:8.0: IDREF attribute idref references an unknown ID "art3333"
     films4dtd.xml - invalid
     
     
     

Nous verrons dans la série 3 d'exercices, avec les transformations XSL, comment ajouter automatiquement les trois lettres art pour les attributs id et idfref, même si on peut le faire sous éditeur avec Edition/Remplacer tout ou avec un outil en ligne de commande comme sed ou perl en mode -i -e.

Il est clair qu'on ne peut pas parler de la grammaire d'un fichier XML, même si on précise DTD ou XSD car les exemples précécents montrent qu'on peut définir plusieurs grammaires pour lesquelles un même fichier XML est valide. C'est pourquoi on ne doit jamais dire qu'un fichier fichier XML est valide sans préciser la grammaire utilisée alors qu'il est tout-à-fait normal de dire qu'un fichier est bien formé sans rien préciser d'autre.

Voici les grammaires utilisées :

films2.dtd       films3.dtd       films2.xsd       films3.xsd       

 

3. Lecture de grammaires courantes de petite taille

Ecrire un fichier cv_minimal.xml minimal valide pour la grammaire cv.dtd.

Quels sont tous les éléments possibles qu'on peut utiliser dans un fichier XHTML 1.0 strict ? Quel élément peut avoir le plus d'attributs ? On commencera par donner leur nombre avant d'en fournir une liste alphabétique.

Comparer les éléments posibles en XHTML 1.0 strict et XHTML 1.0 Transitionnel. Comparer les éléments posibles en XHTML 1.0 strict et HTML 5..

Y a-t-il des grammaires pour les documents Microsoft Office et Open Office/Libre Office ? En DTD ou XSD ? Et au NCBI, pour les formats de données bioinformatiques ? Et pour UNIPROT ? Et pour EMBL-EBI ?

Solution :  

3.1 Un fichier CV minimal

A la lecture de cv_minimal.xml on pourra constater que si la structure imposée est respectée, le remplissage laisse à désirer. Mais au moins les éléments et attributs obligatoires sont présents, même s'ils ne sont pas renseignés. Avec une grammaire XSD on pourrait imposer d'avoir au moins 1 caractère par champ (!), ce qui éviterait les informations vides.


     <?xml version="1.0" encoding="ISO-8859-1" ?>
     <!-- Fichier cv_minimal.xml  -->
     <!DOCTYPE cv SYSTEM "Dtd/cv.dtd">
     <cv>
        <titre></titre>
        <cvnom></cvnom>
        <etatcivil>
            <nom></nom>
            <prenom></prenom>
            <naissance></naissance>
            <situation></situation>
        </etatcivil>
        <formations>
           <formation date-iso="" date="" datefin="" intitule="" description="" />
        </formations>
        <connaissances>
        </connaissances>
        <professionnel>
           <experience date-iso="" date="" datefin="" client="" entreprise="" fonction="">
              <missions>
                <mission></mission>
              </missions>
              <environnement>
                   <technique type="0" nom="" description="" />
              </environnement>
           </experience>
        </professionnel>
     </cv>
     

3.2 Eléments et attributs en XHTML 1.0 Strict

Il faut bien sûr disposer de la DTD du langage pour réaliser cette partie d'exercice. Heureusement, le W3C nous la met à disposition à l'adresse http://www.w3.org/TR/xhtml1/dtds.html et une copie locale est Dtd/xhtml1-strict.dtd. Pour compter et trier les éléments, les commandes Unix nommées grep, wc et sort sont tout-à fait indiquées 


     $gh>  grep "ELEMENT" Dtd/xhtml1-strict.dtd | wc -l
     
     77
     
     $gh>  grep "ELEMENT" Dtd/xhtml1-strict.dtd | sort
     
     <!ELEMENT a %a.content;>
     <!ELEMENT abbr %Inline;>   <!-- abbreviation -->
     <!ELEMENT acronym %Inline;>   <!-- acronym -->
     <!ELEMENT address %Inline;>
     <!ELEMENT area EMPTY>
     <!ELEMENT base EMPTY>
     <!ELEMENT bdo %Inline;>  <!-- I18N BiDi over-ride -->
     <!ELEMENT big %Inline;>   <!-- bigger font -->
     <!ELEMENT b %Inline;>   <!-- bold font -->
     <!ELEMENT blockquote %Block;>
     <!ELEMENT body %Block;>
     <!ELEMENT br EMPTY>   <!-- forced line break -->
     <!ELEMENT button %button.content;>  <!-- push button -->
     <!ELEMENT caption  %Inline;>
     <!ELEMENT cite %Inline;>   <!-- citation -->
     <!ELEMENT code %Inline;>   <!-- program code -->
     <!ELEMENT col      EMPTY>
     <!ELEMENT colgroup (col)*>
     <!ELEMENT dd %Flow;>
     <!ELEMENT del %Flow;>
     <!ELEMENT dfn %Inline;>   <!-- definitional -->
     <!ELEMENT div %Flow;>  <!-- generic language/style container -->
     <!ELEMENT dl (dt|dd)+>
     <!ELEMENT dt %Inline;>
     <!ELEMENT em %Inline;>   <!-- emphasis -->
     <!ELEMENT fieldset (#PCDATA | legend | %block; | form | %inline; | %misc;)*>
     <!ELEMENT form %form.content;>   <!-- forms shouldn't be nested -->
     <!ELEMENT h1  %Inline;>
     <!ELEMENT h2 %Inline;>
     <!ELEMENT h3 %Inline;>
     <!ELEMENT h4 %Inline;>
     <!ELEMENT h5 %Inline;>
     <!ELEMENT h6 %Inline;>
     <!ELEMENT head (%head.misc;,
     <!ELEMENT hr EMPTY>
     <!ELEMENT html (head, body)>
     <!ELEMENT i %Inline;>   <!-- italic font -->
     <!ELEMENT img EMPTY>
     <!ELEMENT input EMPTY>     <!-- form control -->
     <!ELEMENT ins %Flow;>
     <!ELEMENT kbd %Inline;>  <!-- something user would type -->
     <!ELEMENT label %Inline;>
     <!ELEMENT legend %Inline;>     <!-- fieldset label -->
     <!ELEMENT li %Flow;>
     <!ELEMENT link EMPTY>
     <!ELEMENT map ((%block; | form | %misc;)+ | area+)>
     <!ELEMENT meta EMPTY>
     <!ELEMENT noscript %Block;>
     <!ELEMENT object (#PCDATA | param | %block; | form | %inline; | %misc;)*>
     <!ELEMENT ol (li)+>
     <!ELEMENT optgroup (option)+>   <!-- option group -->
     <!ELEMENT option (#PCDATA)>     <!-- selectable choice -->
     <!ELEMENT param EMPTY>
     <!ELEMENT p %Inline;>
     <!ELEMENT pre %pre.content;>
     <!ELEMENT q %Inline;>   <!-- inlined quote -->
     <!ELEMENT samp %Inline;>   <!-- sample -->
     <!ELEMENT script (#PCDATA)>
     <!ELEMENT select (optgroup|option)+>  <!-- option selector -->
     <!ELEMENT small %Inline;>   <!-- smaller font -->
     <!ELEMENT span %Inline;> <!-- generic language/style container -->
     <!ELEMENT strong %Inline;>   <!-- strong emphasis -->
     <!ELEMENT style (#PCDATA)>
     <!ELEMENT sub %Inline;> <!-- subscript -->
     <!ELEMENT sup %Inline;> <!-- superscript -->
     <!ELEMENT table
     <!ELEMENT tbody    (tr)+>
     <!ELEMENT td       %Flow;>
     <!ELEMENT textarea (#PCDATA)>     <!-- multi-line text field -->
     <!ELEMENT tfoot    (tr)+>
     <!ELEMENT thead    (tr)+>
     <!ELEMENT th       %Flow;>
     <!ELEMENT title (#PCDATA)>
     <!ELEMENT tr       (th|td)+>
     <!ELEMENT tt %Inline;>   <!-- fixed pitch font -->
     <!ELEMENT ul (li)+>
     <!ELEMENT var %Inline;>   <!-- variable -->
     

Par contre pour bien présenter ces éléments et compter le nombre d'attributs par éléments, il vaut mieux écrire un programme comme notre analyseur de dtd.

3.3 Comparaison des éléments en XHTML 1.0 Strict, Transitionnel et HTML5

A l'aide des deux fichiers grammaires officielles issues de http://www.w3.org/TR/xhtml1/dtds.html dont strict.dtd et trans.dtd sont des copies locales, il est facile d'écrire un programme de comparaison des divers éléments. Voir par exemple notre comparateur de DTD.

Les principaux éléments absents de XHTML 1.0 Strict sont donc applet, center et font.

HTML5 n'est pas défini de façon rigoureuse aujourd'hui, la grammaire utilisée dans le comparateur est donc provisoire...

3.4 Grammaires pour les suite Office et les formats bioinformatiques

Un document pour Open Office est nommé opendocument. Il n'y a pas une grammaire mais plein de grammaires au format XSD, accessibles par exemple sur le site schemacentral. On pourra au passage regarder ce qu'est uno.

Un document pour Microsoft Office correspond aussi aujourd'hui à ce qu'on nomme OOXML. On peut trouver les grammaires associées, là encore sous forme de schémas XSD, sur le site officiel Microsoft (archive locale).

Le NCBI fournit une page et des outils pour XML, respectivement aux adresses ToolBox XML et ncbixml.txt. Une longue liste de DTD associées est disponible à l'adresse dtd mais le NCBI fournit aussi des schémas, sur le site, dans le sous-répertoire schema.

La recherche du mot XML dans la documentation d'Uniprot renvoie la page query xml qui montre qu'Uniprot est très actif au niveau XML. Ainsi la page xml_news recense les changements les plus récents. On remarquera que sur la page des téléchargements des bases de données figurent les schémas XSD...

Un example de DTD associée à une entrée Uniprot est consultable sur code.google.com.

L'EMBL-EBI n'est pas en reste avec sa page de documentation XML et son convertisseur XML.

 

4. Lecture de grammaires courantes de grande taille

Quels sont tous les éléments possibles qu'on peut utiliser dans un fichier SVG selon la norme SVG 1.1 du 16 aout 2011 ? Quel élément peut avoir le plus d'attribut ? On commencera par donner leur nombre avant d'en fournir une liste alphabétique. Reprendre ensuite avec les fichiers RDF.

Solution :  

Avec grep et wc, rien de plus simple pour compter les éléments  :


     > grep "ELEMENT" svg11-flat-20110816_elts.txt | wc -l
     80
     
     > grep "ELEMENT" svg11-flat-20110816_elts.txt
     
     <!ELEMENT %SVG.altGlyphDef.qname; %SVG.altGlyphDef.content; >
     <!ELEMENT %SVG.altGlyphItem.qname; %SVG.altGlyphItem.content; >
     <!ELEMENT %SVG.altGlyph.qname; %SVG.altGlyph.content; >
     <!ELEMENT %SVG.animateColor.qname; %SVG.animateColor.content; >
     <!ELEMENT %SVG.animateMotion.qname; %SVG.animateMotion.content; >
     <!ELEMENT %SVG.animate.qname; %SVG.animate.content; >
     <!ELEMENT %SVG.animateTransform.qname; %SVG.animateTransform.content; >
     <!ELEMENT %SVG.a.qname; %SVG.a.content; >
     <!ELEMENT %SVG.circle.qname; %SVG.circle.content; >
     <!ELEMENT %SVG.clipPath.qname; %SVG.clipPath.content; >
     <!ELEMENT %SVG.color-profile.qname; %SVG.color-profile.content; >
     <!ELEMENT %SVG.cursor.qname; %SVG.cursor.content; >
     <!ELEMENT %SVG.defs.qname; %SVG.defs.content; >
     <!ELEMENT %SVG.desc.qname; %SVG.desc.content; >
     <!ELEMENT %SVG.ellipse.qname; %SVG.ellipse.content; >
     <!ELEMENT %SVG.feBlend.qname; %SVG.feBlend.content; >
     <!ELEMENT %SVG.feColorMatrix.qname; %SVG.feColorMatrix.content; >
     <!ELEMENT %SVG.feComponentTransfer.qname; %SVG.feComponentTransfer.content; >
     <!ELEMENT %SVG.feComposite.qname; %SVG.feComposite.content; >
     <!ELEMENT %SVG.feConvolveMatrix.qname; %SVG.feConvolveMatrix.content; >
     <!ELEMENT %SVG.feDiffuseLighting.qname; %SVG.feDiffuseLighting.content; >
     <!ELEMENT %SVG.feDisplacementMap.qname; %SVG.feDisplacementMap.content; >
     <!ELEMENT %SVG.feDistantLight.qname; %SVG.feDistantLight.content; >
     <!ELEMENT %SVG.feFlood.qname; %SVG.feFlood.content; >
     <!ELEMENT %SVG.feFuncA.qname; %SVG.feFuncA.content; >
     <!ELEMENT %SVG.feFuncB.qname; %SVG.feFuncB.content; >
     <!ELEMENT %SVG.feFuncG.qname; %SVG.feFuncG.content; >
     <!ELEMENT %SVG.feFuncR.qname; %SVG.feFuncR.content; >
     <!ELEMENT %SVG.feGaussianBlur.qname; %SVG.feGaussianBlur.content; >
     <!ELEMENT %SVG.feImage.qname; %SVG.feImage.content; >
     <!ELEMENT %SVG.feMergeNode.qname; %SVG.feMergeNode.content; >
     <!ELEMENT %SVG.feMerge.qname; %SVG.feMerge.content; >
     <!ELEMENT %SVG.feMorphology.qname; %SVG.feMorphology.content; >
     <!ELEMENT %SVG.feOffset.qname; %SVG.feOffset.content; >
     <!ELEMENT %SVG.fePointLight.qname; %SVG.fePointLight.content; >
     <!ELEMENT %SVG.feSpecularLighting.qname; %SVG.feSpecularLighting.content; >
     <!ELEMENT %SVG.feSpotLight.qname; %SVG.feSpotLight.content; >
     <!ELEMENT %SVG.feTile.qname; %SVG.feTile.content; >
     <!ELEMENT %SVG.feTurbulence.qname; %SVG.feTurbulence.content; >
     <!ELEMENT %SVG.filter.qname; %SVG.filter.content; >
     <!ELEMENT %SVG.font-face-format.qname; %SVG.font-face-format.content; >
     <!ELEMENT %SVG.font-face-name.qname; %SVG.font-face-name.content; >
     <!ELEMENT %SVG.font-face.qname; %SVG.font-face.content; >
     <!ELEMENT %SVG.font-face-src.qname; %SVG.font-face-src.content; >
     <!ELEMENT %SVG.font-face-uri.qname; %SVG.font-face-uri.content; >
     <!ELEMENT %SVG.font.qname; %SVG.font.content; >
     <!ELEMENT %SVG.foreignObject.qname; %SVG.foreignObject.content; >
     <!ELEMENT %SVG.glyph.qname; %SVG.glyph.content; >
     <!ELEMENT %SVG.glyphRef.qname; %SVG.glyphRef.content; >
     <!ELEMENT %SVG.g.qname; %SVG.g.content; >
     <!ELEMENT %SVG.hkern.qname; %SVG.hkern.content; >
     <!ELEMENT %SVG.image.qname; %SVG.image.content; >
     <!ELEMENT %SVG.linearGradient.qname; %SVG.linearGradient.content; >
     <!ELEMENT %SVG.line.qname; %SVG.line.content; >
     <!ELEMENT %SVG.marker.qname; %SVG.marker.content; >
     <!ELEMENT %SVG.mask.qname; %SVG.mask.content; >
     <!ELEMENT %SVG.metadata.qname; %SVG.metadata.content; >
     <!ELEMENT %SVG.missing-glyph.qname; %SVG.missing-glyph.content; >
     <!ELEMENT %SVG.mpath.qname; %SVG.mpath.content; >
     <!ELEMENT %SVG.path.qname; %SVG.path.content; >
     <!ELEMENT %SVG.pattern.qname; %SVG.pattern.content; >
     <!ELEMENT %SVG.polygon.qname; %SVG.polygon.content; >
     <!ELEMENT %SVG.polyline.qname; %SVG.polyline.content; >
     <!ELEMENT %SVG.radialGradient.qname; %SVG.radialGradient.content; >
     <!ELEMENT %SVG.rect.qname; %SVG.rect.content; >
     <!ELEMENT %SVG.script.qname; %SVG.script.content; >
     <!ELEMENT %SVG.set.qname; %SVG.set.content; >
     <!ELEMENT %SVG.stop.qname; %SVG.stop.content; >
     <!ELEMENT %SVG.style.qname; %SVG.style.content; >
     <!ELEMENT %SVG.svg.qname; %SVG.svg.content; >
     <!ELEMENT %SVG.switch.qname; %SVG.switch.content; >
     <!ELEMENT %SVG.symbol.qname; %SVG.symbol.content; >
     <!ELEMENT %SVG.textPath.qname; %SVG.textPath.content; >
     <!ELEMENT %SVG.text.qname; %SVG.text.content; >
     <!ELEMENT %SVG.title.qname; %SVG.title.content; >
     <!ELEMENT %SVG.tref.qname; %SVG.tref.content; >
     <!ELEMENT %SVG.tspan.qname; %SVG.tspan.content; >
     <!ELEMENT %SVG.use.qname; %SVG.use.content; >
     <!ELEMENT %SVG.view.qname; %SVG.view.content; >
     <!ELEMENT %SVG.vkern.qname; %SVG.vkern.content; >
     

Pour les attributs et entités, avec notre analyseur de DTD les chose se compliquent. Voir analyse SVG DTD.

 

5. Conversions entres grammaires DTD et XSD ; vérification de grammaires

Peut-on facilement convertir une grammaire DTD en grammaire XSD ? Si oui quel convertisseur peut-on utiliser ? Si non, expliquez pourquoi.

Peut-on facilement convertir une grammaire XSD en grammaire DTD ? Si oui quel convertisseur peut-on utiliser ? Si non, expliquez pourquoi.

Solution :  

La syntaxe DTD est tellement simple qu'il est facile de la convertir en syntaxe XSD, par exemple avec trang :


     # génération de grammaire DTD à partir de fichier(s) XML via trang, forme longue
     
     java -jar $trangPath trang.jar -I xml -O dtd -i encoding=ISO8859-15 serv00.xml services.dtd
     
     # génération de grammaire XSD à partir de fichier(s) XML via trang, forme courte
     
     trang serv00.xml services.xsd
     

De la même façon, la syntaxe XSD est tellement complexe qu'il est facile de trouver quelque chose qui ne se convertit pas en syntaxe DTD, par exemple la cardinalité maxOccurs="15".

Remarque : trang s'installe tout simplement sous Ubuntu via sudo apt-get install trang.

 

6. Contraintes et facettes dans les schémas XSD

Ecrire une grammaire XSD qui oblige à décrire une séquence fasta avec un identifiant ID qui correspond à l'expression régulière ^[A-U]{1,3}\d{5}$ et une séquence SEQ d'acides aminés d'une longueur d'au moins 20 AA.

L'ancienne numérotation des plaques minéralogiques se composait de trois parties (chiffres,lettres,département). Ecrire une grammaire XSD correspondante et des exemples de fichiers "voitures" ou "cartes grises". Reprendre avec la nouvelle numérotation des plaques françaises.

Solution :  

Exercice non corrigé (volontairement).

 

7. Autres grammaires dont Relax NG ; espaces de noms

Un collègue vient de me fournir une grammaire validateur.rnc pour des fichiers XML comme paradis.xml. Le seul problème est qu'il s'agit d'un schéma Relax NG comme il dit. Comment peut-on s'en servir ? Peut-on le convertir en DTD, en XSD ?

Solution :  

Facile, y'a qu'à installer trang !

La transformation, une fois trang installé, est assurée par :


     trang -I rnc -O xsd validateur.rnc validateur.xsd
     

Voici le fichier rnc original :


     # RelaxNg Schema compact syntax
     
     start = element instance
     {
         attribute nom{xsd:string},
         attribute nbgroupes{xsd:unsignedInt},
        attribute nbattributs{xsd:unsignedInt},
        attribute nbentités{xsd:unsignedInt},
        element données{
            element groupes
            {
     
              element groupe{
                 attribute id{IdGroupe},
                 attribute nom{xsd:string}
              }*
            },
            # correspond aux colonnes
            element attributs
            {
               element attribut{
                  attribute id{IdAttribut},
                 attribute nom{xsd:string}
     
              }*
            },
            # correspond aux lignes
            element entités{
           element entité{
                 attribute id{IdEntite},
                 attribute ref{RefGroupe},
                 attribute nom{xsd:string},
                 # correspond aux cellules
                 # ici on peut ommettre la reference si vides on conserve
                 #les élements valuationPositives et valuationNégatives si pas d'attributs pour plus de visibilité
                 element valuationsPositives{
                    attribute refs{RefsAttributs}?
                 },
                 element valuationsNégatives{
                    attribute refs{RefsAttributs}?
                 }
     
              }*
           }
        },
        # en complément
        element résultats{
           element statistiques{
              element   redondance{
                 attribute pourcentage{pourcentage},
                 element entités{
                    attribute refs{RefsEntites}
                 }*
              },
              element   impossibilités{
                 element entités{
                    attribute refs{RefsEntites}
                 }*
              }
           },
           element caractérisations{
              element groupe{
                 attribute ref{RefGroupe},
                 #mise sous forme text "&" equiv. "et" "|" equiv. "ou" et "~" equiv. "non"
                 #et on conserve les élements groupe pour plus de visibilité si pas de formule
                 (element formule{xsd:string})*
              }*
            }
        }?
     }
     
     
     # Types simples
     
     IdGroupe = xsd:ID { pattern = 'g[1-9][0-9]*' }
     RefGroupe = xsd:IDREF { pattern = 'g[1-9][0-9]*' }
     RefsGroupes = xsd:IDREFS { pattern = 'g[1-9][0-9]*( g[1-9][0-9]*)*' }
     IdAttribut = xsd:ID { pattern = 'a[1-9][0-9]*' }
     RefsAttributs = xsd:IDREFS { pattern = 'a[1-9][0-9]*( a[1-9][0-9]*)*' }
     IdEntite= xsd:ID { pattern = 'g[1-9][0-9]*e[1-9][0-9]*' }
     RefsEntites = xsd:IDREFS { pattern = 'g[1-9][0-9]*e[1-9][0-9]*( g[1-9][0-9]*e[1-9][0-9]*)*' }
     
     pourcentage = xsd:unsignedInt
     {
         maxInclusive = '100'
     }
     
     

et sa traduction en xsd par trang  :


     <?xml version="1.0" encoding="UTF-8"?>
     <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
       <!-- RelaxNg Schema compact syntax -->
       <xs:element name="instance">
         <xs:complexType>
           <xs:sequence>
             <xs:element ref="données"/>
             <xs:element minOccurs="0" ref="résultats"/>
           </xs:sequence>
           <xs:attribute name="nom" use="required" type="xs:string"/>
           <xs:attribute name="nbgroupes" use="required" type="xs:unsignedInt"/>
           <xs:attribute name="nbattributs" use="required" type="xs:unsignedInt"/>
           <xs:attribute name="nbentités" use="required" type="xs:unsignedInt"/>
         </xs:complexType>
       </xs:element>
       <xs:element name="données">
         <xs:complexType>
           <xs:sequence>
             <xs:element ref="groupes"/>
             <xs:element ref="attributs"/>
             <xs:element name="entités">
               <xs:complexType>
                 <xs:sequence>
                   <xs:element minOccurs="0" maxOccurs="unbounded" ref="entité"/>
                 </xs:sequence>
               </xs:complexType>
             </xs:element>
           </xs:sequence>
         </xs:complexType>
       </xs:element>
       <xs:element name="groupes">
         <xs:complexType>
           <xs:sequence>
             <xs:element minOccurs="0" maxOccurs="unbounded" name="groupe">
               <xs:complexType>
                 <xs:attribute name="id" use="required" type="IdGroupe"/>
                 <xs:attribute name="nom" use="required" type="xs:string"/>
               </xs:complexType>
             </xs:element>
           </xs:sequence>
         </xs:complexType>
       </xs:element>
       <xs:element name="attributs">
         <xs:complexType>
           <xs:sequence>
             <xs:element minOccurs="0" maxOccurs="unbounded" ref="attribut"/>
           </xs:sequence>
         </xs:complexType>
       </xs:element>
       <xs:element name="attribut">
         <xs:complexType>
           <xs:attribute name="id" use="required" type="IdAttribut"/>
           <xs:attribute name="nom" use="required" type="xs:string"/>
         </xs:complexType>
       </xs:element>
       <xs:element name="entité">
         <xs:complexType>
           <xs:sequence>
             <xs:element ref="valuationsPositives"/>
             <xs:element ref="valuationsNégatives"/>
           </xs:sequence>
           <xs:attribute name="id" use="required" type="IdEntite"/>
           <xs:attribute name="ref" use="required" type="RefGroupe"/>
           <xs:attribute name="nom" use="required" type="xs:string"/>
         </xs:complexType>
       </xs:element>
       <xs:element name="valuationsPositives">
         <xs:complexType>
           <xs:attribute name="refs" type="RefsAttributs"/>
         </xs:complexType>
       </xs:element>
       <xs:element name="valuationsNégatives">
         <xs:complexType>
           <xs:attribute name="refs" type="RefsAttributs"/>
         </xs:complexType>
       </xs:element>
       <xs:element name="résultats">
         <xs:complexType>
           <xs:sequence>
             <xs:element ref="statistiques"/>
             <xs:element ref="caractérisations"/>
           </xs:sequence>
         </xs:complexType>
       </xs:element>
       <xs:element name="statistiques">
         <xs:complexType>
           <xs:sequence>
             <xs:element ref="redondance"/>
             <xs:element ref="impossibilités"/>
           </xs:sequence>
         </xs:complexType>
       </xs:element>
       <xs:element name="redondance">
         <xs:complexType>
           <xs:sequence>
             <xs:element minOccurs="0" maxOccurs="unbounded" name="entités">
               <xs:complexType>
                 <xs:attribute name="refs" use="required" type="RefsEntites"/>
               </xs:complexType>
             </xs:element>
           </xs:sequence>
           <xs:attribute name="pourcentage" use="required" type="pourcentage"/>
         </xs:complexType>
       </xs:element>
       <xs:element name="impossibilités">
         <xs:complexType>
           <xs:sequence>
             <xs:element minOccurs="0" maxOccurs="unbounded" name="entités">
               <xs:complexType>
                 <xs:attribute name="refs" use="required" type="RefsEntites"/>
               </xs:complexType>
             </xs:element>
           </xs:sequence>
         </xs:complexType>
       </xs:element>
       <xs:element name="caractérisations">
         <xs:complexType>
           <xs:sequence>
             <xs:element minOccurs="0" maxOccurs="unbounded" name="groupe">
               <xs:complexType>
                 <xs:sequence>
                   <xs:element minOccurs="0" maxOccurs="unbounded" ref="formule"/>
                 </xs:sequence>
                 <xs:attribute name="ref" use="required" type="RefGroupe"/>
               </xs:complexType>
             </xs:element>
           </xs:sequence>
         </xs:complexType>
       </xs:element>
       <xs:element name="formule" type="xs:string"/>
       <!-- Types simples -->
       <xs:simpleType name="IdGroupe">
         <xs:restriction base="xs:ID">
           <xs:pattern value="g[1-9][0-9]*"/>
         </xs:restriction>
       </xs:simpleType>
       <xs:simpleType name="RefGroupe">
         <xs:restriction base="xs:IDREF">
           <xs:pattern value="g[1-9][0-9]*"/>
         </xs:restriction>
       </xs:simpleType>
       <xs:simpleType name="RefsGroupes">
         <xs:restriction base="xs:IDREFS">
           <xs:pattern value="g[1-9][0-9]*( g[1-9][0-9]*)*"/>
         </xs:restriction>
       </xs:simpleType>
       <xs:simpleType name="IdAttribut">
         <xs:restriction base="xs:ID">
           <xs:pattern value="a[1-9][0-9]*"/>
         </xs:restriction>
       </xs:simpleType>
       <xs:simpleType name="RefsAttributs">
         <xs:restriction base="xs:IDREFS">
           <xs:pattern value="a[1-9][0-9]*( a[1-9][0-9]*)*"/>
         </xs:restriction>
       </xs:simpleType>
       <xs:simpleType name="IdEntite">
         <xs:restriction base="xs:ID">
           <xs:pattern value="g[1-9][0-9]*e[1-9][0-9]*"/>
         </xs:restriction>
       </xs:simpleType>
       <xs:simpleType name="RefsEntites">
         <xs:restriction base="xs:IDREFS">
           <xs:pattern value="g[1-9][0-9]*e[1-9][0-9]*( g[1-9][0-9]*e[1-9][0-9]*)*"/>
         </xs:restriction>
       </xs:simpleType>
       <xs:simpleType name="pourcentage">
         <xs:restriction base="xs:unsignedInt">
           <xs:maxInclusive value="100"/>
         </xs:restriction>
       </xs:simpleType>
     </xs:schema>
     

 

8. Questions diverses

Comment fait-on pour tester si un fichier DTD est valide ? Et un fichier XSD ? On pourra utiliser bad.dtd et bad.xsd avec respectivement bad_dtd.xml et bad_xsd.xml.

Quelles sont les différences entre XSD 1.0 et XSD 1.1 ?

Faut-il toujours écrire <!DOCTYPE... pour tester si un fichier est valide par rapport à un fichier DTD donné ?

Quelle est la différence entre SVG et Tiny SVG ? Quelles sont leurs grammaires ?

Solution :  

Exercice volontairement non corrigé.

 

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)