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 :
- des déclarations d'éléments,
- des déclarations d'attributs,
- des déclarations
d'entités :
- internes XML,
- externes XML ou non XML.
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
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 <i> </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)
- l'unicité des clefs,
- les contraintes de référence.
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">
- les références se font par &nom_entité;
- les définitions circulaires sont interdites,
- le développement se fait à la demande,
- ils sont utilisables dans les documents XML.
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 :
- il peut contenir un prologue (encodage),
- pas de référence à une DTD,
- il doit être bien formé, c'est à dire contenir un élément complet,
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 "á"> <!ENTITY Aacute "Á"> <!ENTITY acirc "â"> <!ENTITY Acirc "Â"> <!ENTITY agrave "à"> <!ENTITY Agrave "À"> <!ENTITY aring "å"> <!ENTITY Aring "Å"> <!ENTITY atilde "ã"> <!ENTITY Atilde "Ã"> <!ENTITY auml "ä"> <!ENTITY Auml "Ä"> <!ENTITY aelig "æ"> <!ENTITY AElig "Æ"> <!ENTITY ccedil "ç"> <!ENTITY Ccedil "Ç"> <!ENTITY eth "ð"> <!ENTITY ETH "Ð"> <!ENTITY eacute "é"> <!ENTITY Eacute "É"> <!ENTITY ecirc "ê"> <!ENTITY Ecirc "Ê"> <!ENTITY egrave "è"> <!ENTITY Egrave "È"> <!ENTITY euml "ë"> <!ENTITY Euml "Ë"> <!ENTITY iacute "í"> <!ENTITY Iacute "Í"> <!ENTITY icirc "î"> <!ENTITY Icirc "Î"> <!ENTITY igrave "ì"> <!ENTITY Igrave "Ì"> <!ENTITY iuml "ï"> <!ENTITY Iuml "Ï"> <!ENTITY ntilde "ñ"> <!ENTITY Ntilde "Ñ"> ...
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.