Présentation des DTD (« Document Type Definition »)

Introduction

Composantes d'une DTD

♦ Les DTD viennent de SGML.

♦ La version XML est une simplification de la version SGML.

♦ Dans une DTD on trouve :

Lien entre XML et DTD

<?xml version="1.0"
    encoding="iso-8859-1"
    standalone="no" ?>

<!DOCTYPE stock
    SYSTEM "http://monserveur.fr/dtd/stock.dtd"
    [ ... déclarations ... ] >
...

♦ La partie « [déclarations] » est optionnelle.

♦ La partie « SYSTEM ... » est optionnelle.

♦ L'URL peut être relative. Elle est, dans ce cas, interprétée à partir de la position du document XML.

Définition des éléments

Déclaration

<!ELEMENT nom-d'élément modèle-de-contenu >

Les attributs d'un élément sont déclarés dans un deuxième temps.

Contenu libre

Dans ce cadre il n'y a aucune contrainte sur le contenu d'un élément :

<!ELEMENT  doc  ANY>

Exemple :

<doc>Ceci est une <i>documentation</i>
très simple</doc>

Contenu vide

C'est la contrainte la plus forte, le contenu doit être vide :

<!ELEMENT  toc  EMPTY>

Exemples :

<toc></toc>
<toc/>
<toc />

Contre exemples (attention aux blancs entre les éléments) :

<toc> </toc>
<toc> 
</toc>

Contenu textuel

L'élément doit contenir du texte (éventuellement vide) analysable dans l'encodage du document (Parsed Character Data) :

<!ELEMENT  comment  (#PCDATA)>

Exemples :

<comment>un commentaire sur
la balise <![CDATA[<p>]]> et &lt;i&gt;
</comment>

<!-- no comment -->
<comment></comment>
<comment/>

Contenu composé

Le contenu est composé de plusieurs parties ordonnées :

<!ELEMENT  produit  (nom,prix,#PCDATA)>

<!ELEMENT  nom      (#PCDATA)>
<!ELEMENT  prix     (#PCDATA)>

Exemple :

<produit>
   <nom>XML par la pratique</nom>
   <prix>20</prix>
   Comment programmer des applications XML.
</produit>

Cette version est préférable :

<!ELEMENT  produit  (nom,prix,comment)>

<!ELEMENT  nom      (#PCDATA)>
<!ELEMENT  prix     (#PCDATA)>
<!ELEMENT  comment  (#PCDATA)>

Contenu alternatif

Plusieurs choix sont possibles pour construire le contenu :

<!ELEMENT  reponse  (oui|non)>
<!ELEMENT  oui      EMPTY>
<!ELEMENT  non      EMPTY>

Exemples :

<reponse> <oui/> </reponse>
<reponse> <non></non> </reponse>

Contre exemples :

<reponse> <oui/><non/> </reponse>
<reponse> <oui/><oui/> </reponse>
<reponse/>

Contenu combiné

L'utilisation des parenthèses permet de combiner les contenus composés et alternatifs :

<!ELEMENT  personne  (nom,(adr|email))>

Exemple :

<personne>
   <nom>...</nom> <adr>49 Bd de la Révolution</adr>
</personne>
<personne>
   <nom>...</nom> <email>tartanpion@...</email>
</personne>

Deux notations équivalentes :

<!ELEMENT  personne  (((age,adr)|(age,email)),nom)>
<!ELEMENT  personne  (age,(adr|email),nom)>

Répétition de contenu

Les caractères « ? », « + », « * » ajoutés à un contenu permettent de le répéter respectivement de 0 à 1 fois (?), de 1 à n fois (+) ou de 0 à n fois (*).

<!ELEMENT  chapitre (
   nom,date?,auteur*,intro?,
   (nom-de-section,corps-de-section)+
   )>

Document XML valide :

<chapitre>
   <nom>Utiliser les DTD</nom>
   <date>10/11/2002</date> <!-- optionnel -->
   <!-- 0 à n fois -->
   <auteur>...</auteur><auteur>...</auteur>      
   <!-- optionnel -->
   <intro>...</intro> 
   <!-- 1 à n fois -->
   <nom-de-section>Préambule</nom-de-section>
   <corps-de-section>...</corps-de-section>
</chapitre>

Contenu mixte

Le contenu mixte dénote un mélange entre texte et éléments XML :

<!ELEMENT  p  (#PCDATA|b|i|tt)* >

Document XML valide :

<p>Un <i>exemple</i> <b>important</b> de paragraphe <tt>HTML</tt></p>

On peut noter sur cet exemple les six noeuds fils de l'élément p (trois de type texte et trois de type élément).

Définition des attributs

Déclaration d'attribut

Syntaxe :

<!ATTLIST  nom_élément
     nom_attribut_1  type_attribut_1  déclar_de_défaut
     nom_attribut_2  type_attribut_2  déclar_de_défaut
     ...
     >

♦ Les déclarations de défaut :

'valeur' valeur par défaut,
#REQUIRED l'attribut doit être renseigné,
#IMPLIED l'attribut est facultatif,
#FIXED 'valeur' l'attribut a tjrs la même valeur

Contenu textuel (CDATA)

Les attributs de type CDATA contiennent des chaînes de caractères (les < et & ne sont pas analysés).

<!ELEMENT  a  ANY>
<!ATTLIST  a  b  CDATA  #IMPLIED
              c  CDATA  'Hello'
              >

Document XML valide :

<a b="coucou" c="10"> ... </a>
<a b="coucou" />
<a/>

Identifiant (ID) et référence (IDREF)

Un attribut de type ID ou IDREF contient respectivement une clef ou une référence à une clef. La validation va vérifier (dans un seul document)

Exemple :

<!ELEMENT  p  (#PCDATA)>
<!ATTLIST  p  id  ID  #IMPLIED>

<!ELEMENT  xref  (#PCDATA)>
<!ATTLIST  xref  ref  IDREF  #REQUIRED>

Document XML valide :

<p id='intro'> Ceci est une intro... </p>
...

Ce détail est expliqué dans
<xref ref="intro">l'introduction</xref>.

Identificateurs XML (NMTOKEN)

Un attribut de type NMTOKEN ou NMTOKENS contient un ou plusieurs identificateurs XML séparés par des blancs (espace, tabulation et/ou retour chariot) :

<!ELEMENT  exo  (#PCDATA)>
<!ATTLIST  exo  niveau  NMTOKENS  #IMPLIED>

Fragment d'un document XML valide :

<exo niveau="facile"> ... </exo>

<exo niveau="difficile facultatif"> ... </exo>

Liste d'identificateurs

Exemple :

<!ELEMENT  prix  (#PCDATA)>
<!ATTLIST  prix  monnaie  (euros|francs)  #REQUIRED>

Fragment d'un document XML valide :

<prix monnaie="euros"> 10 </prix>

Les valeurs possibles doivent être des identificateurs (tokens) XML.

Les listes de valeurs n'existent que pour les attributs.

Définition des entités

Les entités internes

Les entités internes sont des macros qui permettent de factoriser et de paramétrer les documents XML.

<!ENTITY  nom_entité  "valeur">

Exemple :

<!ENTITY  dom.luminy  "univ-mrs.fr" >
<!ENTITY  dom.dil     "dil.&dom.luminy;" >

Fragment de document XML valide :

<email> massat@&dom.dil; </email>

<!-- erreur -->
<a href="http://www.&dom.dil;">...</a> 

Les entités externes XML

Les entités externes XML permettent d'inclure des documents XML identifiés par une URL.

<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE livre SYSTEM "livre.dtd"
   [
   <!ENTITY  chap1  SYSTEM  "chapitre1.xml.inc">
   <!ENTITY  chap2  SYSTEM  "chapitre2.xml.inc">
   ]
   >

<livre> &chap1; &chap2; </livre>

Contraintes sur le document XML inclu :

Les entités externes non XML

Une entité externe non XML peut contenir n'importe quoi (image, son, données, etc.). Nous devons donc, au préalable, définir un type :

<!NOTATION  nom_du_type  SYSTEM  "url_associé_au_type">

Par exemple :

<!NOTATION  JPEG   SYSTEM  "JPG">
<!NOTATION  JPG    SYSTEM  "JPG">
<!NOTATION  PNG    SYSTEM  "http://www.w3.org/TR/REC-png">
<!NOTATION  SWF    SYSTEM  "http://www.macromedia.com/software/flash">

Le nom du type n'est qu'un raccourci. C'est l'URL qui identifie le type.

On peut ensuite définir l'entité externe non XML :

<!ENTITY  maison  SYSTEM "maison.jpg"  NDATA jpeg>

La référence &maison; est impossible (ce n'est pas du XML). Son utilisation doit passer par un attribut typé « entité externe non XML » :

DTD : | <!ELEMENT  image  EMPTY>
      | <!ATTLIST  image  src  ENTITY  #REQUIRED>
      
XML : | <image src="maison"/> <!-- pas de &..; -->

L'attribut peut également être typé ENTITIES, on peut dans ce cas lui associer plusieurs entités externes non XML.

Les clauses INCLUDE et IGNORE

Deux exemples :

<![IGNORE[

   ... partie de la DTD à ignorer ...

]]>

et

<![INCLUDE[

   ... partie de la DTD à traiter ...

]]>

Les entités paramètres

Les entités paramètres internes

Les entités paramètres sont des macros qui permettent de factoriser et de paramétrer les DTD. Syntaxe :

<!ENTITY  %  nom_entité  "valeur">

Le référencement se note %nom_entité;

<!ENTITY  %  statut
             "statut (public|privé) #IMPLIED 'public'">

<!ELEMENT  article  (#PCDATA)>
<!ATTLIST  article  date  CDATA  #IMPLIED
                    %statut;
                    >

Les entités paramètres externes

Les entités paramètres externes permettent d'inclure des DTD externes.

<!ENTITY  %  chapitre
    SYSTEM  "chapitre.mod">

<!ENTITY  %  tableau
    SYSTEM  "http://monserveur.fr/dtd/tableau.mod">

%chapitre;

%tableau;

Partie interne / externe

<!DOCTYPE livre SYSTEM "livre.dtd"
   [
   ... partie interne ...
   ]
   >

♦ La partie interne est traitée avant la partie externe.

♦ Il est donc possible de faire varier la DTD à partir des déclarations internes.

♦ Les clauses IGNORE et INCLUDE ne sont pas utilisables dans la partie interne.

Les sections conditionnelles

La DTD :

<!ENTITY % attr.date 'IGNORE'>

<!ELEMENT  para   ANY>
<!ELEMENT  titre  ANY>

<![%attr.date;[

    <!ATTLIST para  date CDATA #IMPLIED>
    <!ATTLIST titre date CDATA #IMPLIED>

]]>

Le document XML :

<!DOCTYPE  para  SYSTEM "essai.dtd"
   [
   <!ENTITY % attr.date 'INCLUDE'>
   ]>

...

La DTD DocBook

<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
          "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" >

<article>
  <title>foo</title>

  <section>
    <title>sect1</title>
    <para>This is a paragraph.</para>
    <blockquote><para>This is a block quote.</para></blockquote>

    <section>
      <title>section 1.1</title>
      <para>This is a paragraph with a <citetitle>title
      citation</citetitle>, a <command>hello</command>, and some
      <computeroutput>computer output</computeroutput>. </para>

      <itemizedlist>
        <listitem><para>this is a list item.</para></listitem>
      </itemizedlist>

    </section>
  </section>
</article>

Les déclarations de caractères

...

<!ENTITY aacute "&#x00E1;"> <!ENTITY Aacute "&#x00C1;">
<!ENTITY acirc  "&#x00E2;"> <!ENTITY Acirc  "&#x00C2;">
<!ENTITY agrave "&#x00E0;"> <!ENTITY Agrave "&#x00C0;">
<!ENTITY aring  "&#x00E5;"> <!ENTITY Aring  "&#x00C5;">
<!ENTITY atilde "&#x00E3;"> <!ENTITY Atilde "&#x00C3;">
<!ENTITY auml   "&#x00E4;"> <!ENTITY Auml   "&#x00C4;">
<!ENTITY aelig  "&#x00E6;"> <!ENTITY AElig  "&#x00C6;">
<!ENTITY ccedil "&#x00E7;"> <!ENTITY Ccedil "&#x00C7;">
<!ENTITY eth    "&#x00F0;"> <!ENTITY ETH    "&#x00D0;">
<!ENTITY eacute "&#x00E9;"> <!ENTITY Eacute "&#x00C9;">
<!ENTITY ecirc  "&#x00EA;"> <!ENTITY Ecirc  "&#x00CA;">
<!ENTITY egrave "&#x00E8;"> <!ENTITY Egrave "&#x00C8;">
<!ENTITY euml   "&#x00EB;"> <!ENTITY Euml   "&#x00CB;">
<!ENTITY iacute "&#x00ED;"> <!ENTITY Iacute "&#x00CD;">
<!ENTITY icirc  "&#x00EE;"> <!ENTITY Icirc  "&#x00CE;">
<!ENTITY igrave "&#x00EC;"> <!ENTITY Igrave "&#x00CC;">
<!ENTITY iuml   "&#x00EF;"> <!ENTITY Iuml   "&#x00CF;">
<!ENTITY ntilde "&#x00F1;"> <!ENTITY Ntilde "&#x00D1;">

...

Les déclarations de notations

...

<!ENTITY % local.notation.class "">
<!ENTITY % notation.class
        "BMP| CGM-CHAR | CGM-BINARY | CGM-CLEAR | DITROFF | DVI
        | EPS | EQN | FAX | GIF | GIF87a | GIF89a 
        | JPG | JPEG | IGES | PCX
        | PIC | PNG | PS | SGML | TBL | TEX | TIFF | WMF | WPG
        | linespecific
        %local.notation.class;">

<!NOTATION BMP          PUBLIC "+//ISBN 0-7923-9432-1:: ...">

<!NOTATION CGM-CHAR     PUBLIC "ISO 8632/2//NOTATION ...">
<!NOTATION CGM-BINARY   PUBLIC "ISO 8632/3//NOTATION ...">
<!NOTATION CGM-CLEAR    PUBLIC "ISO 8632/4//NOTATION ...">

<!NOTATION DITROFF      SYSTEM "DITROFF">

<!NOTATION DVI          SYSTEM "DVI">
<!NOTATION EPS          PUBLIC "+//ISBN 0-201-18127-4:: ...">

...

Déclarations des éléments

<!ELEMENT title (%title.char.mix;)*>
<!ATTLIST title
        %pagenum.attrib;        %common.attrib;
        %title.role.attrib;     %local.title.attrib; >

<!ELEMENT subtitle (%title.char.mix;)*>
<!ATTLIST subtitle
        %common.attrib;           %subtitle.role.attrib;
        %local.subtitle.attrib;   >

On remarque dans cet extrait que le contenu des éléments n'est jamais donnée directement. Les rédacteurs de DTD passent généralement par une entité paramètre.

Déclarations des contenu d'éléments

<!ENTITY % pagenum.attrib "pagenum CDATA #IMPLIED">

<!ENTITY % local.common.attrib "">
<!ENTITY % common.attrib
   "id           ID                          #IMPLIED
    revisionflag (changed|added|deleted|off) #IMPLIED
    %local.common.attrib;" >

<!ENTITY % local.title.char.mix "">
<!ENTITY % title.char.mix
    "#PCDATA|%gen.char.class;|%link.char.class;
     |%tech.char.class;|%docinfo.char.class;
     |%inlineobj.char.class; %local.title.char.mix;">

<!ENTITY % local.gen.char.class "">
<!ENTITY % gen.char.class
    "abbrev|acronym|citetitle|emphasis|footnote|phrase
     |quote|trademark %local.gen.char.class;">

Les entités paramètres local.xxx permettent d'étendre cette DTD en ajoutant du contenu et/ou des attributs.