XML, DTD et structure Travaux Pratiques

Inria

Apprenez à maîtriser la syntaxe XML : un petit exercice plus difficile qu'il n'y paraît.

Concevez une instance XML et sa DTD. Créez un petit bout de code pour analyser votre document.

Prérequis

  • Connaître HTML peut aider
  • Savoir écrire une classe Java

Cours

  • XML et DTD

Syntaxe XML et structuration de l'information

Mise en jambe : le jeu des 16 erreurs

Notre ami Forrest a décidé d'écrire ses mémoires en XML. Aidez-le à corriger son document en conservant la structure logique et le contenu autant que faire se peut.

Forrest : sa vie, son oeuvre

Le fichier tp/xml/forrest.xml ne s'affichera pas dans votre navigateur car il contient des erreurs. Enregistrez-le, corrigez-le, et utilisez le parseur intégré à votre navigateur préféré pour vous aider.

Ci-dessous son contenu lu avec un décodage iso-8859-1 :

<?xml version="1.0" encoding="UTF-8" standalone="standalone"?>
<?xml-stylesheet type="text/xsl" href="fg.xsl"?>
<!-- à relire -->
<?robots index="yes" follow="no"?>
<document>
    <titre style="bold" style="big">Mes mémoires</titre>
    <auteur>
        <nom>Gump</nom>
        <prénom>Forrest</prénom>
    <auteur>
    <description xmlns="http://www.w3.org/1999/xhtml"
        style="bold" Style="big" xml:space="preserve">
        <!-- à partir d'ici, on peut utiliser 
        des éléments HTML <!-- et d'autres aussi -->
        c'est pratique pour du contenu
        documentaire -->
        <p xml:space="default" align=center>Ma maman disait
            toujours : &#xA; "<i>la vie c'est comme une 
            bo&icirc;te de <b>chocolat</i>, on ne sait jamais
            sur quoi on va tomber</b>".</p>
        <hr width/>
        <a  xlink:href="bubbagump.avi"
            xmlns:xlink="http://www.w3.org/1999/xlink"
            href="bubbagump.avi"
            xlink:role="mon film">
            <object xmlns:xlink=""
                    xlink:href="bubbagump.avi"/>
        </a>
        <script language="JavaScript">
        <![CDATA[
            function check() {
                for (int i=10; i>0; i++) {
                    if ( a[b[i]]>5 ) break;
                }
            }
        ]]>
        <!-- vérifier si la boucle doit s'écrire 
        avec i-- et pas i++ -->
        </script>
        <p>La suite, je ne m'en souviens plus...
    </description>
    <xml_parse processor="JAXP"/>
</document>
<remarques>
    Mon document ne parse pas
</remarques>
<!-- il y a quelques erreurs -->
fin du document


Survolez les numéros pour afficher une explication sur les erreurs.

<?xml version="1.0" encoding="1iso-8859-1" standalone="2yes"?>
<?xml-stylesheet type="text/xsl" href="fg.xsl"?>
<!-- à relire -->
<?robots index="yes" follow="no"?>
<document>
    <titre 3style="bold" Style="big">Mes mémoires</titre>
    <auteur>
        <nom>Gump</nom>
        <prénom>Forrest</prénom>
    4</auteur>
    <description xmlns="http://www.w3.org/1999/xhtml"
        style="bold" Style="big" xml:space="preserve">
        <!-- à partir d'ici, on peut utiliser
        des éléments HTML 5<!&#45;&#45; et d'autres aussi &#45;&#45;>
        c'est pratique pour du contenu
        documentaire -->
        <p xml:space="default" 6align='center'>Ma maman disait
            toujours : &#xA; "<i>la vie c'est comme une
            7boîte de 8<b>chocolat</b>, on ne sait jamais
            sur quoi on va tomber</i>".</p>
        <hr 9width=""/>
        <a  xlink:href="bubbagump.avi"
            xmlns:xlink="http://www.w3.org/1999/xlink"
            href="bubbagump.avi"
            xlink:role="mon film">
            <object 10
                    xlink:href="bubbagump.avi"/>
        </a>
        <script language="JavaScript">
        <![CDATA[
            function check() {
                for (int i=10; i>0; i++) {
                    if ( a[b[i11]]>]]>5 ) break;
                }
            }

        <!-- vérifier si la boucle doit s'écrire
        avec 12i&#45;&#45; et pas i++ -->
        </script>
        <p>La suite, je ne m'en souviens plus...13</p>
    </description>
    14<xml_parse processor="JAXP"/>
    15<remarques>
        Mon document ne parse pas
    </remarques>
</document>
<!-- il y a quelques erreurs -->
16

Fichier corrigé: tp/xml/forrest-ok.xml

Si le fichier corrigé ne se charge pas dans votre browser, ce n'est pas dû à une erreur syntaxique XML mais probablement dû au comportement de votre navigateur qui réagit sur l'instruction de traitement <?xsl-stylesheet?> et ne trouve pas la ressource référencée.

Essayez de mettre entre commentaire cette instruction de traitement pour voir comment votre navigateur va afficher le document.

Une fois le document corrigé, répondez aux questions suivantes :

  • Est-ce que ce document est bien formé (oui/non) ?
    Oui, puisque toutes les erreurs ont été corrigées.
  • Est-ce que ce document est valide (oui/non) ?
    On ne sait pas : il faudrait connaître le shéma pour pouvoir se prononcer.

Programmez un parseur pour valider l'instance avec une DTD. On utilisera JAXP (package javax.xml.parsers).

import javax.xml.parsers.*;

public class MonParserValidantQuiValide {

    public static void main( String[] args ) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setValidating( true );
        DocumentBuilder parser = factory.newDocumentBuilder();
        parser.parse( args[0] );
    }
}

Pour lancer le programme :

java -cp . MonParserValidantQuiValide forrest.xml

Ecrivez une DTD pour ce document et modifiez-le pour qu'elle soit référencée dans l'instance XML (<!DOCTYPE ...>).

Utilisez votre parseur validant pour vérifier que votre instance est conforme à la DTD.

<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT a (object)>
<!ATTLIST a
    href NMTOKEN #REQUIRED
    xlink:href NMTOKEN #REQUIRED
    xlink:role CDATA #REQUIRED
    xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink"
>
<!ELEMENT auteur (nom,prénom)>
<!ELEMENT b (#PCDATA)>
<!ELEMENT description (a|hr|p|script)*>
<!ATTLIST description
    Style NMTOKEN #REQUIRED
    style NMTOKEN #REQUIRED
    xml:space NMTOKEN #REQUIRED
    xmlns CDATA #FIXED "http://www.w3.org/1999/xhtml"
>
<!ELEMENT document (titre,auteur,description,xml_parse,remarques)>
<!ELEMENT hr EMPTY>
<!ATTLIST hr width NMTOKEN #REQUIRED>
<!ELEMENT i (#PCDATA|b)*>
<!ELEMENT nom (#PCDATA)>
<!ELEMENT object EMPTY>
<!ATTLIST object xlink:href NMTOKEN #REQUIRED>
<!ELEMENT p (#PCDATA|i)*>
<!ATTLIST p
    align NMTOKEN #IMPLIED
    xml:space NMTOKEN #IMPLIED
>
<!ELEMENT prénom (#PCDATA)>
<!ELEMENT remarques (#PCDATA)>
<!ELEMENT script (#PCDATA)>
<!ATTLIST script language NMTOKEN #REQUIRED>
<!ELEMENT titre (#PCDATA)>
<!ATTLIST titre
    Style NMTOKEN #REQUIRED
    style NMTOKEN #REQUIRED
>
<!ELEMENT xml_parse EMPTY>
<!ATTLIST xml_parse processor NMTOKEN #REQUIRED>

Insérez la ligne 2 dans le fichier XML :

<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
<!DOCTYPE document SYSTEM "forrest-ok.dtd">
<?xml-stylesheet type="text/xsl" href="fg.xsl"?>
<!-- à relire -->
<?robots index="yes" follow="no"?>
<document>
    ...

Structuration des données

Vous êtes l'informaticien d'un Zoo. On vous demande d'organiser les données du Zoo en XML.

Concevez une petite instance en XML qui permet de gérer les animaux du zoo (primates : gorilles, babouins...; fauves : lions, tigres...), leurs caractéristiques physiques (nom, sexe, taille, poids, date de naissance, etc) et éventuellement des avertissements (animaux dangereux, ne pas nourrir, ne pas entrer dans la cage, etc).

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE zoo SYSTEM "zoo.dtd" [
    <!ENTITY % notations SYSTEM "notations.ent">
%notations;
    <!ENTITY flipper.jpg SYSTEM "flipper.jpg" NDATA jpg>
    <!ENTITY oum.jpg SYSTEM "oum.jpg" NDATA jpg>
    <!ENTITY ecco.jpg SYSTEM "ecco.jpg" NDATA jpg>
]>
<!-- Un petit Zoo avec quelques animaux -->
<zoo>
    <info>Ouvert tous les jours de 8h00 à 19h00</info>
    <info><img src="nourrir.gif" />Il est <b>interdit</b> de nourrir les animaux&#127;&#128;.</info>
    <aquarium>
        <mammifères-marins>
            <dauphins>
                <dauphin id="jhgtr13" photo="flipper.jpg" date-naissance="1997-4-1">
                    <nom>Flipper</nom>
                    <sexe>M</sexe>
                    <taille unité="cm">215</taille>
                    <poids unité="kg">105</poids>
                </dauphin>
                <dauphin id="lkjh45" photo="ecco.jpg" date-naissance="2003-10-23">
                    <nom>Ecco</nom>
                    <sexe>F</sexe>
                    <taille unité="cm">202</taille>
                    <poids unité="kg">98</poids>
                </dauphin>
                <dauphin id="kjlhy90" photo="oum.jpg" date-naissance="1996-12-25">
                    <nom>Oum</nom>
                    <sexe>F</sexe>
                    <!-- c'est mon préféré -->
                    <taille unité="cm">295</taille>
                    <poids unité="kg" status="mesure approximative">190<!-- il faut refaire la pesée --></poids>
                </dauphin>
            </dauphins>
        </mammifères-marins>
        <poissons>
            <sélaciens>
                <danger>Il est <b>interdit</b> de nager avec les requins.</danger>
                <requin id="plojk09" espèce="marteau" date-naissance="1998-6-5">
                    <nom>Oussama</nom>
                    <sexe>M</sexe>
                    <taille unité="cm">455</taille>
                    <poids unité="kg">540</poids>
                    <commentaire>A tendance a se jeter contre les murs
                        <![CDATA[<<< marteau & cinglé !!! >>>]]>
                        <!-- Il faudra bien le faire piquer un jour -->
                    </commentaire>
                </requin>
                <requin id="vgyuh43" espèce="requin bleu" nom-savant="carcharias glaucus" date-naissance="2004-1-13">
                    <nom>Saddam</nom>
                    <sexe>M</sexe>
                    <taille unité="cm">355</taille>
                    <poids unité="kg" status="">425</poids>
                </requin>
            </sélaciens>
        </poissons>
    </aquarium>
</zoo>

Ecrivez la DTD qui va avec. Que faut-il ajouter dans le document pour aider un parseur à valider le document ?

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!ENTITY nourrir.gif SYSTEM "nourrir.gif" NDATA gif>

<!ENTITY % block "p | info | danger | attention">
<!ENTITY % inline "b | i | em | strong | stabilo | img">
<!ENTITY % attractions "aquarium?, vivarium?, enclos?, volière?">
<!ENTITY % animal "nom, sexe, taille, poids, commentaire?">
<!ENTITY % animal-attr "
    id		ID #REQUIRED
    espèce		CDATA #IMPLIED
    nom-savant	CDATA #IMPLIED
    photo		ENTITY #IMPLIED
    date-naissance  CDATA #REQUIRED
">
<!ENTITY % u-attr "
    unité		CDATA #REQUIRED
    status		CDATA #IMPLIED
">

<!ELEMENT p (#PCDATA | %inline;)*>
<!ELEMENT info (#PCDATA | %inline;)*>
<!ELEMENT danger (#PCDATA | %inline;)*>
<!ELEMENT attention (#PCDATA | %inline;)*>

<!ELEMENT b (#PCDATA | %inline;)*>
<!ELEMENT i (#PCDATA | %inline;)*>
<!ELEMENT em (#PCDATA | %inline;)*>
<!ELEMENT strong (#PCDATA | %inline;)*>
<!ELEMENT stabilo (#PCDATA | %inline;)*>
<!ELEMENT img EMPTY>
<!ATTLIST img src ENTITY #REQUIRED>

<!ELEMENT zoo ((%block;)*, %attractions;)>

<!ELEMENT aquarium (mammifères-marins?, poissons?)>
<!ELEMENT mammifères-marins (dauphins?, baleines?, orques?)>
<!ELEMENT poissons (sélaciens?)>

<!ELEMENT vivarium (serpents?, arachnéens?)>
<!ELEMENT serpents (boas?)>
<!ELEMENT arachnéens (mygales?)>

<!ELEMENT enclos (primates?, fauves?)>
<!ELEMENT primates (gorilles?, orangs-outans?)>
<!ELEMENT fauves (tigres?, lions?)>

<!ELEMENT volière (oiseaux-terrestres?, oiseaux-aquatiques?, rapaces?)>
<!ELEMENT oiseaux-terrestres (autruches?)>
<!ELEMENT oiseaux-aquatiques (pingouins?, manchots?)>
<!ELEMENT rapaces (aigles?)*>

<!ELEMENT dauphins (%block; | dauphin)+>
<!ELEMENT dauphin (%animal;)>
<!ATTLIST dauphin %animal-attr;>

<!ELEMENT baleines (%block; | baleine)+>
<!ELEMENT baleine (%animal;)>
<!ATTLIST baleine %animal-attr;>

<!ELEMENT orques (%block; | orque)+>
<!ELEMENT orque (%animal;)>
<!ATTLIST orque %animal-attr;>

<!ELEMENT sélaciens (%block; | requin)+>
<!ELEMENT requin (%animal;)>
<!ATTLIST requin %animal-attr;>

<!ELEMENT boas (%block; | boa)+>
<!ELEMENT boa (%animal;)>
<!ATTLIST boa %animal-attr;>

<!ELEMENT mygales (%block; | mygale)+>
<!ELEMENT mygale (%animal;)>
<!ATTLIST mygale %animal-attr;>

<!ELEMENT gorilles (%block; | gorille)+>
<!ELEMENT gorille (%animal;)>
<!ATTLIST gorille %animal-attr;>

<!ELEMENT orangs-outans (%block; | orang-outan)+>
<!ELEMENT orang-outan (%animal;)>
<!ATTLIST orang-outan %animal-attr;>

<!ELEMENT tigres (%block; | tigre)+>
<!ELEMENT tigre (%animal;)>
<!ATTLIST tigre %animal-attr;>

<!ELEMENT lions (%block; | lion)+>
<!ELEMENT lion (%animal;)>
<!ATTLIST lion %animal-attr;>

<!ELEMENT autruches (%block; | autruche)+>
<!ELEMENT autruche (%animal;)>
<!ATTLIST autruche %animal-attr;>

<!ELEMENT pingoins (%block; | pingoin)+>
<!ELEMENT pingoin (%animal;)>
<!ATTLIST pingoin %animal-attr;>

<!ELEMENT manchots (%block; | manchot)+>
<!ELEMENT manchot (%animal;)>
<!ATTLIST manchot %animal-attr;>

<!ELEMENT aigles (%block; | aigle)+>
<!ELEMENT aigle (%animal;)>
<!ATTLIST aigle %animal-attr;>

<!ELEMENT nom (#PCDATA)>
<!ELEMENT sexe (#PCDATA)>
<!ELEMENT taille (#PCDATA)>
<!ATTLIST taille %u-attr;>

<!ELEMENT poids (#PCDATA)>
<!ATTLIST poids %u-attr;>

<!ELEMENT commentaire (#PCDATA | %block;)*>

La DTD est complétée avec cette petite entité :

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!NOTATION jpg SYSTEM "images/jpeg">
<!NOTATION gif SYSTEM "images/gif">

Pour aider un parseur à valider le document avec cette DTD, il faut ajouter la déclaration <!DOCTYPE zoo SYSTEM "zoo.dtd"> dans l'instance XML. Mais ce n'est pas suffisant pour que la validation soit réalisée automatiquement. En l'occurrence, les navigateurs lisent la DTD mais ne valident pas nécessairement. Il faut donc utiliser le parseur validant réalisé précédemment.

Programmez un parseur pour valider l'instance avec la DTD. On utilisera JAXP (package javax.xml.parsers).

tp/xml/MonParserValidantQuiValide.java.

Pour lancer le programme :

java -cp . MonParserValidantQuiValide zoo.xml

Si vous n'avez jamais eu d'erreur, modifiez votre instance en introduisant volontairement des données en contradiction avec votre grammaire. Lancez à nouveau la validation. Qu'indique le parseur ?

Si on introduit des erreurs qui rendent le document non conforme à la DTD, (voir tp/xml/zoo-ko.xml) une exception est lancée :.

bash-2.05b$ java -cp . MonParserValidantQuiValide zoo-ko.xml
Warning: validation was turned on but an org.xml.sax.ErrorHandler was not set, which is probably not what is desired.
Parser will use a default ErrorHandler to print the first 10 errors.
Please call the 'setErrorHandler' method to fix this.
Error: URI=file:/path/to/zoo-ko.xml Line=13: Element "zoo" does not allow "mammifères-marins" here.
Error: URI=file:/path/to/zoo-ko.xml Line=36: Element "zoo" does not allow "poissons" here.

Modifiez votre programme pour qu'il affiche le nom de l'élément racine de votre document XML (package org.w3c.dom).

Il suffit de récupérer le résultat de l'analyse dans un org.w3c.dom.Document :

    import org.w3c.dom.*;
...
    Document doc = parser.parse( args[0] );
    System.out.println( doc.getDocumentElement().getNodeName() );