XML en L2, université d'Angers
gilles.hunault@univ-angers.fr
T.P. numéro 3
Table des matières cliquable
1. Créer un document XML qui respecte une grammaire DTD
2. Créer un document XML qui respecte une grammaire XSD
4. Validité suivant la grammaire
5. Créer des grammaires DTD et XSD
6. Non unicité des grammaires DTD et XSD
Il est possible d'afficher toutes les solutions via ?solutions=1 et de les masquer via ?solutions=0 .
1. Créer un document XML qui respecte une grammaire DTD
Nous admettrons pour ce qui suit qu'une molécule est définie par une liste d'atomes avec le nom des atomes, leur notation et le nombre de ces atomes fournis en attributs. Par exemple la molécule d'eau H2O est définie par l'atome de nom hydrogène, de notation H en nombre 2 et par l'atome de nom oxygène, de notation O et en nombre 1 (qui peut donc être omis). Après avoir lu soigneusement le fichier suivant nommé molecule.dtd, écrire un fichier eau.xml valide pour cette grammaire DTD. On utilisera un outil en ligne de commande pour vérifier cette validité. On pourra ignorer les accents.
Fichier molecule.dtd :
<!ELEMENT molecule (atome)+ > <!ELEMENT atome EMPTY > <!ATTLIST atome nom CDATA #REQUIRED > <!ATTLIST atome lettre CDATA #REQUIRED > <!ATTLIST atome nombre CDATA "1" >Est-ce que cette grammaire DTD autorise les chaines vides pour les noms, lettres et nombres ?
Est-ce qu'il faut respecter l'ordre des attributs tel qu'il est défini dans la grammaire DTD ?
Solution : afficher la solution
Voici un fichier eau.xml possible :
<?xml version="1.0" ?> <molecule> <atome nom="Hydrogene" lettre="H" nombre="2" /> <atome nom="Oxygene" lettre="O" nombre="1" /> </molecule>On peut vérifier la validité de ce fichier pour la grammaire molecule.dtd via les commandes suivantes :
xmllint --dtdvalid molecule.dtd eau.xml xmlstarlet val -d molecule.dtd eau.xml xmlstarlet val -e -d molecule.dtd eau.xml # s'il y a es erreursHélas, oui cette grammaire DTD autorise les chaines vides pour les noms, lettres et les nombres car CDATA, comme #PCDATA inclut la chaine vide. On pourra s'en rendre compte avec le fichier suivant eauvide.xml qui est valide pour cette grammaire. Attention : une chaine de caractères réduite à un espace est aussi valide, mais vraiment peu informative...
De la même façon, l'ordre des attributs est libre, à condition qu'un attribut n'apparaisse pas deux fois, comme le montre le fichier suivant, qui est valide pour la DTD considérée :
Fichier eaudtdatt.xml :
<?xml version="1.0" ?> <!DOCTYPE molecule SYSTEM "molecule.dtd"> <molecule> <atome lettre="" nom="" nombre="" /> <atome nombre="" nom="" lettre="" /> </molecule>Voici le message d'erreur en cas de duplication d'attribut, comme c'est le cas pour le fichier eaudtdatt2.xml :
<?xml version="1.0" ?> <!-- fichier eaudtdatt2.xml --> <!DOCTYPE molecule SYSTEM "molecule.dtd"> <molecule> <atome lettre="" nom="" nombre="" /> <atome nombre="" nom="" lettre="" nombre = "" /> </molecule>$gh> xmlstarlet val -e -d molecule.dtd eaudtdatt2.xml eaudtdatt2.xml:5.51: Attribute nombre redefined <atome nombre="" nom="" lettre="" nombre = "" /> ^ eaudtdatt2.xml - invalid
2. Créer un document XML qui respecte une grammaire XSD
On décide maintenant d'utiliser la grammaire molecule.xsd suivante pour stocker les mêmes informations.
Fichier molecule.xsd :
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="molecule"> <xsd:complexType> <xsd:sequence> <xsd:element maxOccurs="unbounded" ref="atome"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="atome"> <xsd:complexType> <xsd:sequence> <xsd:element ref="nom"/> <xsd:element ref="nombre"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="nom"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:string"> <xsd:attribute name="lettre" use="required" type="xsd:string"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element> <xsd:element name="nombre" type="xsd:integer"/> </xsd:schema>Ecrire un fichier eau2.xml valide pour cette grammaire XSD. On utilisera un outil en ligne de commande pour vérifier cette validité. Là encore, on pourra ignorer les accents.
Est-ce que cette grammaire XSD autorise les chaines vides pour les noms, lettres et nombres ?
Solution : afficher la solution
Voici un fichier eau2.xml possible :
<?xml version="1.0" ?> <molecule> <atome> <nom lettre="O">Oxygene</nom> <nombre>1</nombre> </atome> <atome> <nom lettre="H">Hydrogene</nom> <nombre>2</nombre> </atome> </molecule>On peut vérifier la validité de ce fichier pour la grammaire molecule.xsd via les commandes suivantes :
xmllint --noout --schema molecule.xsd eau2.xml xmlstarlet val -s molecule.xsd eau2.xmlHélas, oui cette grammaire XSD autorise les chaines vides pour les noms, lettres, mais pas pour les nombres car xsd:string inclut la chaine vide mais xsd:integer l'interdit. On pourra s'en rendre compte avec le fichier suivant eau3.xml qui est valide pour cette grammaire. Attention : ici aussi une chaine de caractères réduite à un espace est valide, mais vraiment peu informative...
3. DTD et paramètres
On structure un dessin 2D élémentaire selon les règles suivantes. Un dessin est un cercle, un rectangle ou un triangle. Un cercle est défini par un centre et un rayon, un rectangle par son csg (coin supérieur gauche), une longueur et une largeur, un triangle par trois points. Chaque élément graphique peut avoir une couleur parmi les mots prédéfinis bleu, rouge, jaune ou vert. Ecrire un fichier dessin.xml qui dans un viewport bleu de 500 pixels de large et 300 de haut, met un "soleil" jaune de rayon 15 pixels en (450,50), une plage rectangulaire verte qui fait toute la largeur et qui fait 100 pixels de haut. Pour les plus fort(e)s, rajouter une petite étoile de mer rouge en bas à gauche à l'aide de trois triangles bien choisis. A défaut, on placera juste un triangle plein et en rouge. On pourra s'inspirer du dessin ci-dessous et de la syntaxe SVG.
Ecrire ensuite la "vraie" version en SVG de ce dessin.
Comment vérifier que ce dessin est valide au sens de la grammaire de SVG ?
Quel logiciel, du type paint, gimp ou photoshop, permet de lire et d'écrire des fichiers SVG ?
Donner les grammaires DTD et XSD associées au fichier dessinTP.xml. On nommera dessin.dtd et dessin.xsd les fichiers-grammaires correspondants. On essaiera de paramétrer l'attribut couleur qui est commun.
Solution : afficher la solution
Voici un fichier XML possible pour le dessin avec une syntaxe en français adaptée de SVG, nommé dessin.xml
<?xml version="1.0" encoding="ISO-8859-1" ?> <dessins largeur="500px" hauteur="300px"> <dessin> <!-- tout en bleu ciel --> <rectangle xcsg="0" ycsg="0" largeur="500" hauteur="300" couleur="bleu-ciel" /> <!-- le soleil en jaune --> <cercle xcentre="450" ycentre="50" rayon="15" couleur="jaune" /> <!-- la plage en vert --> <rectangle xcsg="0" ycsg="200" largeur="500" hauteur="100" couleur="vert" /> <!-- un triangle rouge --> <triangle couleur="rouge" xpoint1="50" ypoint1="250" xpoint2="75" ypoint2="225" xpoint3="100" ypoint3="250" /> </dessin> </dessins>La "vraie" version dont un rendu est dans dessin1.svg est la suivante
<?xml version="1.0" encoding="ISO-8859-1" ?> <svg xmlns="http://www.w3.org/2000/svg" width="500px" height="300px"> <g> <!-- tout en bleu ciel --> <rect x="0" y="0" width="500" height="300" fill="cyan" /> <!-- le soleil en jaune --> <circle cx="450" cy="50" r="15" fill="yellow" /> <!-- la plage en vert --> <rect x="0" y="200" width="500" height="100" fill="green" /> <!-- un triangle rouge --> <path fill="red" d="M 50,250 L 75,225 L 100, 250 z" /> </g> </svg>Et pour le dessin avec l'étoile dessin2.svg on peut utiliser
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE svg SYSTEM "Dtd/svg.dtd"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="500px" height="300px"> <g> <!-- tout en bleu ciel --> <rect x="0" y="0" width="500" height="300" fill="cyan" /> <!-- le soleil en jaune --> <circle cx="450" cy="50" r="15" fill="yellow" /> <!-- la plage en vert --> <rect x="0" y="200" width="500" height="100" fill="green" /> <!-- l'étoile de mer en rouge avec 2 triangles rouges et un triangle vert --> <path fill="red" d="M 050,250 L 080,265 L 110,250 z" /> <path fill="red" d="M 065,285 L 080,225 L 095,285 z" /> <path fill="green" d="M 065,285 L 080,265 L 095,285 z" /> </g> </svg>Le W3C avec son fameux Markup Validation Service est capable de tester si ce fichier est valide pour la grammaire de SVG.
Au niveau logiciel, c'est sans doute Inkscape qui est le plus complet et le plus agréale à utiliser pour dessiner, lire et écrire des images au format SVG.
Rendu SVG (si le browser le permet) Rendu PNG (copie d'écran) 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 possibles 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
4. Validité suivant la grammaire
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.
Solution : afficher la solution
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 - validPar 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 :
5. Créer des grammaires DTD et XSD
Disons qu'un trajet ferroviaire est représenté schématiquement mais obligatoirement par un numéro identifiant de trajet, un type de train, un lieu de départ et un lieu d'arrivée. Ces informations sont éventuellement complétées, lorsqu'elles sont disponibles, par deux informations ts (pour time stamp en anglais) qui fournissent respectivement la date et heure de départ et la date et heure d'arrivée.
Voici un exemple de fichier XML regroupant deux trajets, nommé trajets.xml.
Fichier trajets.xml :
<trajets> <trajet id="tr02436"> <train>TGV </train> <depart>Angers</depart> <arrive>Paris Montparnasse</arrive> </trajet> <trajet id="tr5897"> <train>Micheline </train> <depart ts="2016-09-08 13:00">Troyes</depart> <arrive ts="2016-09-08 17:08">Dijon</arrive> </trajet> </trajets>Donner pour ce fichier trajets.xml une grammaire DTD minimale et raisonnable qui permet de décrire les trajets ferroviaires puis une grammaire XSD équivalente.
Solution : afficher la solution
On lira attentivement les fichiers ci-dessous.
Grammaire trajets.dtd :
<!ELEMENT trajets (trajet)+ > <!ELEMENT trajet (train,depart,arrive) > <!ELEMENT train (#PCDATA) > <!ELEMENT depart (#PCDATA) > <!ELEMENT arrive (#PCDATA) > <!ATTLIST trajet xmlns CDATA #FIXED '' id NMTOKEN #REQUIRED > <!ATTLIST depart xmlns CDATA #FIXED '' ts CDATA #IMPLIED > <!ATTLIST arrive xmlns CDATA #FIXED '' ts CDATA #IMPLIED >Grammaire trajets.xsd :
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xsd:element name="trajets"> <xsd:complexType> <xsd:sequence> <xsd:element maxOccurs="unbounded" ref="trajet"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="trajet"> <xsd:complexType> <xsd:sequence> <xsd:element ref="train"/> <xsd:element ref="depart"/> <xsd:element ref="arrive"/> </xsd:sequence> <xsd:attribute name="id" use="required" type="xsd:NCName"/> </xsd:complexType> </xsd:element> <xsd:element name="train" type="xsd:NCName"/> <xsd:element name="depart"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:NCName"> <xsd:attribute name="ts"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element> <xsd:element name="arrive"> <xsd:complexType mixed="true"> <xsd:attribute name="ts"/> </xsd:complexType> </xsd:element> </xsd:schema>Au passage, vous aurez remarqué que la grammaire proposée est invalide puisque l'espace de noms proposé (xs) ne correspond pas aux préfixes utilisés (xsd). Il faut donc juste modifier la ligne 1 pour qu'il y ait écrit xmlns:xsd= au lieu de xmlns:xs=.
6. Non unicité des grammaires DTD et XSD
Ecrire une grammaire pour le fichier films2 en DTD puis en XSD. Où y a-t-il des choix à faire ? Pourquoi ne peut-on pas parler de la grammaire DTD d'un fichier ?
Peut-on créer automatiquement des grammaires à partir d'exemples ? Que faut-il attendre de ce genre de production automatique ?
Solution : afficher la solution
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 à films5.xml soit le résultat suivant.
On peut donc écrire la grammaire minimale suivante qui autorise à n'avoir aucun film ni aucun artiste :
<!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 >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 - invalidNous verrons dans la prochaine série 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
Il existe des outils pour créer automatiquement des grammaires à partir d'exemples, comme par exemple trang dont le manuel est ici. Exemples d'utilisation :
# 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 serv00.dtd # génération de grammaire XSD à partir de fichier(s) XML via trang, forme courte trang serv00.xml serv00.xsd
7. Vérification des vérificateurs
Pour vérifier un document XML, on utilise une grammaire DTD ou XSD. Mais comment vérifier une grammaire DTD ou XSD ?
On pourra utiliser les grammaires incorrectes bad.dtd et bad.xsd associées respectivement aux fichiers baddtd.xml et badxsd.xml pour vérifier votre vérification de vérificateurs (!).
Solution : afficher la solution
Exercice volontairement corrigé. Quoique...Venez en T.P. !
8. Rajout de contraintes
Reprendre l'exercice 1 (la molécule) et définir un schéma XSD plus restrictif que la DTD avec les règles suivantes :
- le nom de l'atome doit comporter au moins deux lettres (au fait, pourquoi ?)
- le nombre d'atomes doit être un entier non négatif
- l'attribut lettre de l'atome doit comporter au moins une lettre en majuscule, suivie au maximum d'une lettre en minuscule (pourquoi ?)
Solution : afficher la solution
Exercice volontairement corrigé. Quoique...Venez en T.P. !
Retour à la page principale de (gH)