DTD (Document Type Definition)

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 52

DTD (Document Type Definition)

Le rôle d'une DTD (Document Type Definition) est de définir précisément la structure d'un document. Il s'agit d'un certain
nombre de contraintes que doit respecter un document pour être valide. Ces contraintes spécifient quels sont les
éléments qui peuvent apparaître dans le contenu d'un élément, l'ordre éventuel de ces éléments et la présence de texte
brut. Elles définissent aussi, pour chaque élément, les attributs autorisés et les attributs obligatoires.

1
2

On reprend la petite bibliographie du fichier bibliography.xml déjà utilisée au chapitre précédent. La troisième ligne de ce
fichier est la déclaration de la DTD qui référence un fichier externe bibliography.dtd. Le nom bibliography de l'élément racine
du document apparaît dans cette déclaration juste après le mot clé DOCTYPE.
<!DOCTYPE bibliography SYSTEM "bibliography.dtd">
On présente maintenant le contenu de ce fichier bibliography.dtd qui contient la DTD du fichier bibliography.xml. La syntaxe
des DTD est héritée de SGML et elle est différente du reste du document XML. Il n'y a pas de balises ouvrantes et fermantes.
La DTD contient des déclarations d'éléments et d'attributs délimitées par les chaînes de caractères '<!' et '>'. Un mot clé juste
après la chaîne '<!' indique le type de la déclaration.
3

1. Un premier exemple
La syntaxe et la signification précise de ces déclarations sont explicitées dans ce chapitre.
4

2. Déclaration de la DTD

La déclaration de la DTD du document doit être placée dans le prologue. La DTD peut être interne, externe ou mixte. Elle est interne si elle
est directement incluse dans le document. Elle est externe si le document contient seulement une référence vers un autre document
contenant la DTD. Elle est finalement mixte si elle est constituée d'une partie interne et d'une partie externe. Une DTD est généralement
prévue pour être utilisée pour de multiples documents. Elle est alors utilisée comme DTD externe. En revanche, il est pratique d'inclure
directement la DTD dans le document en phase de développement. La déclaration de la DTD est introduite par le mot clé DOCTYPE et a la
forme générale suivante où root-element est le nom de l'élément racine du document.
<!DOCTYPE root-element ... >
Le nom de l'élément racine est suivi du contenu de la DTD dans le cas d'une DTD interne ou de l'URL du fichier
contenant la DTD dans le cas d'une DTD externe.
5

2.1. DTD interne


Lorsque la DTD est incluse dans le document, sa déclaration prend la forme suivante où son contenu est encadré par des caractères
crochets '[' et ']'.
<!DOCTYPE root-element [ déclarations ]>
Les déclarations déclarations constituent la définition du type du document. Dans l'exemple suivant de DTD, le nom de l'élément racine est
simple. La DTD déclare en outre que cet élément ne peut contenir que du texte (Parsed Characters DATA) et pas d'autre élément.
<!DOCTYPE simple [
<!ELEMENT simple (#PCDATA)>
]>

2.2. DTD externe


Lorsque la DTD est externe, celle-ci est contenue dans un autre fichier dont l'extension est généralement .dtd. Le document XML se
contente alors de donner l'adresse de sa DTD pour que les logiciels puissent y accéder. L'adresse de de la DTD peut être donnée
explicitement par une URL ou par un FPI (Formal Public Indentifier).
Les FPI sont des noms symboliques donnés aux documents. Ils sont utilisés avec des catalogues qui établissent les correspondances entre
ces noms symboliques et les adresses réelles des documents. Lorsqu'un logiciel rencontre un FPI, il parcourt le catalogue pour le résoudre,
c'est-à-dire déterminer l'adresse réelle du document. Les catalogues peuvent contenir des adresses locales et/ou des URL. Ils constituent
donc une indirection qui facilite la maintenance. Lorsqu'un document, une DTD par exemple, est déplacé, il suffit de modifier les catalogues
plutôt que tous les documents qui référencent le document.
6

2.2.1. Adressée par FPI


Les FPI (Formal Public Identifier) sont des identifiants de documents hérités de SGML. Ils sont plutôt remplacés en XML par les URI qui
jouent le même rôle. Ils sont constitués de quatre parties séparées par des chaînes '//' et ils obéissent donc à la syntaxe suivante.
type//owner//desc//lang
Le premier caractère type du FPI est soit le caractère '+' si le propriétaire est enregistré selon la norme ISO 9070 soit le caractère '-' sinon.
Le FPI continue avec le propriétaire owner et la description desc du document. Cette description est formée d'un mot clé suivi d'un texte
libre. Ce mot clé est DTD pour les DTD mais il peut aussi être DOCUMENT, ELEMENTS ou ENTITIES. Le FPI se termine par un code de
langue lang de la norme ISO 639. Lorsque le document appartient à une norme ISO, le premier caractère '+' ainsi que la chaîne '//' suivante
sont supprimés. Des exemples de FPI sont donnés ci-dessous.
-//W3C//DTD XHTML 1.0 Strict//EN
-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN
ISO/IEC 10179:1996//DTD DSSSL Architecture//EN
7

Un FPI peut être converti en URI en utilisant l'espace de noms publicid des URN et en remplaçant chaque chaîne '//' par le caractère ':' et
chaque espace par le caractère '+' comme dans l'exemple ci-dessous.
urn:publicid:-:W3C:DTD+XHTML+1.0+Strict:EN

La déclaration d'une DTD externe peut utiliser un FPI pour désigner la DTD. La référence à un FPI est introduite par le mot clé PUBLIC
suivi du FPI et d'une URL délimitée par des apostrophes ''' ou des guillemets '"'.
L'URL est utilisée dans le cas où le FPI ne permet pas à l'application de retrouver la DTD.
<!DOCTYPE root-element PUBLIC "fpi" "url">
L'exemple suivant est la déclaration typique d'une page HTML qui utilise une des DTD de XHTML.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
8

2.2.2. Adressée par URL

La référence à une URL est introduite par le mot clé SYSTEM suivi de l'URL délimitée par des apostrophes '''
ou des guillemets '"'.
<!DOCTYPE root-element SYSTEM "url">
L'URL url peut être soit une URL complète commençant par http:// ou ftp:// soit plus simplement le nom d'un
fichier local comme dans les exemples suivants.
<!DOCTYPE bibliography SYSTEM
"http://www.omega-one.org/~carton/Enseignement/bibliography.dtd">
<!DOCTYPE bibliography SYSTEM "bibliography.dtd">
9

2.3. DTD mixte


Il est possible d'avoir simultanément une DTD externe adressée par URL ou FPI et des déclarations internes. La DTD globale est alors
formée des déclarations internes suivies des déclarations externes. La déclaration prend alors une des deux formes suivantes On retrouve
un mélange de la syntaxe des DTD externes avec les mots clés SYSTEM et PUBLIC et de la syntaxe des DTD internes avec des
déclarations encadrées par les caractères '[' et ']'.
<!DOCTYPE root-element SYSTEM "url" [ declarations ]>
<!DOCTYPE root-element PUBLIC "fpi" "url" [ declarations ]>

Il n'est pas possible de déclarer plusieurs fois le même élément dans une DTD. Lorsque la DTD est mixte, tout élément doit être déclaré
dans la partie interne ou dans la partie externe mais pas dans les deux. En revanche, il est possible de déclarer plusieurs fois le même
attribut. La première déclaration a priorité. Il est ainsi possible de donner une nouvelle déclaration d'un attribut dans la partie interne
puisque celle-ci est placée avant la partie externe.

Les entités paramètres peuvent également être déclarées plusieurs fois dans une même DTD et c'est encore la première déclaration qui
l'emporte. La DTD suivante déclare l'entité paramètre book.entries égale à la chaîne vide. Cette entité est ensuite utilisée dans la
déclaration de l'élément book. Cette déclaration laisse la possibilité au document principal d'ajouter des enfants à l'élément book en
donnant une nouvelle valeur à l'entité book.entries.
10

La première ligne de cette DTD est une entête XML qui permet de déclarer le codage des caractères.

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


<!-- DTD externe -->
<!-- Entité paramètre pour les enfants à ajouter à l'élément book -->
<!ENTITY % book.entries "">
<!ELEMENT bibliography (book)+>
<!ELEMENT book (title, author, year, publisher, isbn %book.entries;)>
<!ATTLIST book key NMTOKEN #REQUIRED>
<!ATTLIST book lang (fr | en) #IMPLIED>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT year (#PCDATA)>
<!ELEMENT publisher (#PCDATA)>
<!ELEMENT isbn (#PCDATA)>
11

Le document suivant a une DTD mixte dont la partie externe est la DTD précédente. La partie interne de la DTD contient la déclaration de
l'élément url. Elle contient également des nouvelles déclarations de l'entité paramètre book.entries et de l'attribut lang de l'élément book,
qui devient ainsi obligatoire.
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
<!DOCTYPE bibliography SYSTEM "mixed.dtd" [
<!-- Ajout d'un enfant url à l'élément book -->
<!ENTITY % book.entries ", url?">
<!-- Redéclaration de l'attribut lang de l'élément book -->
<!-- L'attribut devient obligatoire -->
<!ATTLIST book lang (fr | en) #REQUIRED>
<!-- Déclaration de l'élément url -->
<!ELEMENT url (#PCDATA)>
]>
12

Comme la valeur donnée à l'entité paramètre book.entries est la chaîne ", url?" (sans les guillemets '"'), la déclaration de l'élément book
dans le fichier mixed.dtd devient équivalente à la déclaration suivante qui autorise un enfant url optionnel.
<!ELEMENT book (title, author, year, publisher, isbn, url?)>
13

3. Contenu de la DTD

Une DTD est constituée de déclarations d'éléments, d'attributs et d'entités. Elle peut aussi contenir des déclarations de
notations mais celles-ci ne sont pas abordées dans cet ouvrage. Chacune de ces déclarations commence par la chaîne '<!'
suivi d'un mot clé qui indique le type de déclaration. Les mots clés possibles sont ELEMENT,
ATTLIST et ENTITY. La déclaration se termine par le caractère '>'.
14

4. Commentaires

Une DTD peut contenir des commentaires qui utilisent la syntaxe des commentaires XML [Section 2.7.5] délimités
par les chaînes de caractères '<!--' et '-->'. Ceux-ci sont placés au même niveau que les déclarations d'éléments, d'attributs
et d'entités. Ils ne peuvent pas apparaître à l'intérieur d'une déclaration.
<!-- DTD pour les bibliographies -->
<!ELEMENT bibliography (book)+>
15

5. Entités

Les entités constituent un mécanisme hérité de SGML. Elles sont des macros semblables aux #define du langage C. Elles
permettent également de réaliser des inclusions de documents comme la directive #include du langage C. Les entités sont
définies dans la DTD du document. Il existe deux types d'entités. Les entités générales, appelées simplement entités dans cet
ouvrage, sont destinées à être utilisées dans le corps du document. Les entités paramètres sont destinées à être utilisées au sein
de la DTD.

Une entité est, en quelque sorte, un nom donné à un fragment de document. Ce fragment peut être donné explicitement à la
définition de l'entité dans la DTD. Il peut également provenir d'un fichier externe. Dans ce cas, la définition de l'entité donne un
FPI et/ou une URL permettant d'accéder au document. Le fragment de document peut être inséré dans le document en utilisant
simplement le nom de l'entité. Lorsque le fragment provient d'un autre fichier, l'utilisation de l'entité provoque l'inclusion du
fichier en question. Le nom de chaque entité générale ou paramètre doit être un nom XML.
16

5.1. Entités générales


Les entités générales sont les entités les plus courantes et les plus utiles puisqu'elles peuvent être utilisées dans le corps du document.

5.1.1. Déclaration et référence


La déclaration d'une entité commence par <!ENTITY suivi du nom de l'entité. Elle prend une des trois formes suivantes où name est le
nom de l'entité, fragment est un fragment de document, fpi et url sont un FPI et une URL.
<!ENTITY name "fragment">
<!ENTITY name SYSTEM "url">
<!ENTITY name PUBLIC "fpi" "url">

Lorsque l'entité est déclarée avec la première syntaxe, elle est dite interne car le fragment est explicitement donné dans la DTD du
document. Lorsqu'elle est déclarée avec une des deux dernières syntaxes, elle est dite externe car le fragment provient d'un autre
document. Ces deux dernières syntaxes sont semblables à la déclaration d'une DTD externe dans un document XML. Les règles pour
l'utilisation des apostrophes ''' et des guillemets '"' sont identiques à celles pour les valeurs d'attributs. Le fragment, le FPI et l'URL
doivent être délimités par une paire d'apostrophes ou de guillemets. Si le fragment est délimité par des apostrophes, les guillemets
peuvent être introduits directement sans entité et inversement.
17

Une entité de nom name est référencée, c'est-à-dire utilisée, par &name; où le nom name de l'entité est encadré par les caractères '&' et
';'. Lorsque le document est traité, la référence à une entité est remplacée par le fragment de document correspondant. Une entité interne
peut être référencée dans les contenus d'éléments et dans les valeurs d'attribut alors qu'une entité externe peut seulement être
référencée dans les contenus d'éléments.
<tag meta="attribute: &name;">Content: &name;</tag>
Entité Caractère
5.1.2. Entités prédéfinies
Il existe des entités prédéfinies permettant d'inclure les caractères spéciaux &lt; <
'<', '>', '&', ''' et '"' dans les contenus d'éléments et dans les valeurs d'attributs.
Ces entités sont les suivantes. &gt; >

&amp; &

&apos; ‘

&quot; “

Tableau 3.1. Entités prédéfinies


18

Les trois entités &lt;, &gt; et &amp; doivent être utilisées aussi bien dans le contenu des éléments que dans les valeurs des attributs
puisque les caractères '<', '>' et '&' ne peuvent pas y apparaître directement. Les deux entités &apos; et &quot; sont uniquement
nécessaires pour inclure le caractère ''' ou le caractère '"' dans la valeur d'un attribut délimitée par le même caractère. Lors de l'utilisation
XPath [Chapitre 6] avec XSLT, il n'est pas rare d'inclure ces deux caractères dans la valeur d'un attribut. Une des deux entités &apos;
ou &quot; devient alors indispensable. L'exemple suivant est extrait d'une feuille de style XSLT. La valeur de l'attribut test est une
expression XPath qui teste si la valeur de la variable string contient le caractère '"'.
<xsl:when test="contains($string, '&quot;')">

Les nombreuses entités prédéfinies en XHTML comme &euro; pour le symbole '€' n'existent pas en XML. La seule façon d'inclure ce
caractère est d'utiliser les notations &#point de code décimal; ou &#xpoint de code hexadécimal;. Il est cependant possible de définir ces
propres entités (cf. ci-dessous).
19

5.1.3. Entités internes


La valeur d'une entité interne est le fragment de document associé à celle-ci lors de sa déclaration. Cette valeur peut contenir des
caractères ainsi que des éléments avec leurs balises. Lorsqu'elle contient des éléments, le fragment doit être bien formé. À toute balise
ouvrante doit correspondre une balise fermante et l'imbrication des balises doit être correcte. Quelques exemples d'entités internes sont
donnés ci-dessous. Le dernier exemple utilise des apostrophes ''' pour délimiter le fragment de document qui contient des guillemets '"'
pour encadrer les valeurs des attributs.
<!ENTITY aka
"also known as">
<!ENTITY euro "&#x20AC;">
<!ENTITY rceil '<phrase condition="html">&#x2309;</phrase>
<phrase condition="fo" role="symbolfont">&#xF8F9;</phrase>'>

Si la DTD contient les déclarations d'entités ci-dessus, Il est possible d'inclure le texte also known as en écrivant seulement &aka; ou
d'inclure un symbole en écrivant &euro;. Les entités internes peuvent être référencées dans les contenus d'éléments mais aussi dans les
valeurs d'attributs.
<price currency="Euro (&euro;)">30 &euro;</price>
20

Il est possible d'utiliser des entités dans la définition d'une autre entité pourvu que ces entités soient également définies. L'ordre de ces
définitions est sans importance car les substitutions sont réalisées au moment où le document est lu par l'analyseur de l'application. Les
définitions récursives sont bien sûr interdites.
<!DOCTYPE book [
<!-- Entités internes -->
<!ENTITY mci "Michel Colucci &aka; 'Coluche'">
<!ENTITY aka "also known as">
]>
<book>&mci;</book>

Il faut faire attention au fait que certaines applications ne gèrent pas ou gèrent mal les entités définies. La solution
est d'ajouter à la chaîne de traitement une première étape consistant à substituer les entités par leurs valeurs pour
obtenir un document intermédiaire sans entités. Le logiciel xmllint peut par exemple réaliser cette opération.
Avec l'option --noent, il écrit sur la sortie standard le document en remplaçant chaque entité par sa valeur.
21

5.1.4. Entités externes


Une entité peut désigner un fragment de document contenu dans un autre fichier. Ce mécanisme permet de répartir un même document
sur plusieurs fichiers comme dans l'exemple suivant. La déclaration utilise alors le mot clé SYSTEM suivi d'une URL qui peut, simplement,
être le nom d'un fichier local. Les entités externes peuvent êtres utilisées pour scinder un document en plusieurs fichiers. Le fichier
principal inclut les différentes parties en définissant une entité externe pour chacune de ces parties. Les entités sont alors utilisées pour
réaliser l'inclusion comme dans l'exemple ci-dessous.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE book [
<!-- Entités externes -->
<!ENTITY chapter1 SYSTEM "chapter1.xml">
<!ENTITY chapter2 SYSTEM "chapter2.xml">
]>
<book>
<!-- Inclusion du fichier chapter1.xml -->
&chapter1;
<!-- Inclusion du fichier chapter2.xml -->
&chapter2;
</book>
22

Chacun des fichiers contenant une entité externe peut avoir une entête. Celle-ci permet par exemple de déclarer un
encodage des caractères différents du fichier principal. Ce mécanisme pour répartir un document en plusieurs fichiers est à
abandonner au profit de XInclude qui est plus pratique.
23

5.2. Entités paramètres


Les entités paramètres sont des entités qui peuvent uniquement être utilisées à l'intérieur de la DTD. La terminologie est historique et
provient de SGML. Ces entités ont le même rôle que les entités générales. Elles sont surtout utilisées pour apporter de la modularité aux
DTD. La déclaration d'une entité paramètre prend une des trois formes suivantes où name est le nom de l'entité, fragment est un
fragment de document, fpi et url sont un FPI et une URL.
<!ENTITY % name "fragment">
<!ENTITY % name SYSTEM "url">
<!ENTITY % name PUBLIC "fpi" "url">
La seule différence avec la déclaration d'une entité générale est la présence du caractère '%' entre le mot clé ENTITY et le nom de l'entité
déclarée. Comme pour les entités générales, l'entité est dite interne lorsqu'elle est déclarée avec la première syntaxe. Elle est dite externe
lorsqu'elle est déclarée avec une des deux dernières syntaxes. Les règles pour l'utilisation des apostrophes ''' et des guillemets '"' sont
identiques à celles pour les valeurs d'attributs ou les entités générales.

L'entité name ainsi déclarée peut être référencée, c'est-à-dire utilisée, par %name; où le nom de l'entité est encadré les caractères '%' et
';'. Les entités paramètres peuvent uniquement être utilisées au sein de la DTD. Lorsque l'entité est interne, elle peut être utilisée dans les
déclarations d'éléments, d'attributs et d'autres entités. Cette utilisation est limitée à la partie externe de la DTD. Lorsque l'entité est
externe, elle est utilisée en dehors des déclarations pour inclure des déclarations provenant du document référencé par l'entité.
L'exemple suivant définit deux entités paramètres idatt et langatt permettant de déclarer des attributs id et xml:lang facilement.
24

<!-- Déclaration de deux entités paramètres -->


<!ENTITY % idatt "id ID #REQUIRED">
<!ENTITY % langatt "xml:lang NMTOKEN 'fr'">
<!-- Utilisation des deux entités paramètres -->
<!ATTLIST chapter %idatt; %langatt;>
<!ATTLIST section %langatt;>

Les entités paramètres ajoutent de la modularité qui est surtout nécessaire dans l'écriture de DTD de grande taille. Dans l'exemple
précédent, l'attribut id pourrait être remplacé partout par un attribut xml:id en changeant uniquement la définition de l'entité paramètre
idatt. Un autre exemple d'utilisation des entités paramètres est donné avec les DTD mixtes. Les entités externes permettent d'inclure
une partie de DTD provenant d'un document externe comme dans l'exemple suivant.

<!-- Entité paramètre pour inclure la DTD principale -->


<!ENTITY % main SYSTEM "main.dtd">
<!-- Inclusion du fichier main.dtd -->
%main;
25

6. Déclaration d'élément
Les déclarations d'éléments constituent le cœur des DTD car elles définissent la structure des documents valides.
Elles spécifient quels doivent être les enfants de chaque élément et l'ordre de ces enfants.
La déclaration d'un élément est nécessaire pour qu'il puisse apparaître dans un document. Cette déclaration
précise le nom et le type de l'élément. Le nom de l'élément doit être un nom XML [Section 2.2.3] et le type
détermine les contenus valides de l'élément. On distingue les contenus purs uniquement constitués d'autres
éléments, les contenus textuels uniquement constitués de texte et les contenus mixtes qui mélangent éléments et
texte. De manière générale, la déclaration d'un élément prend la forme suivante où élément et type sont
respectivement le nom et le type de l'élément. Le type de l'élément détermine quels sont ses contenus autorisés.
<!ELEMENT element type>
26

6.1. Contenu pur d'éléments


Le contenu d'un élément est pur lorsqu'il ne contient aucun texte et qu'il est uniquement constitué d'éléments qui sont ses enfants. Ces
enfants peuvent, à leur tour, avoir des contenus textuels, purs ou mixtes. Un élément de contenu pur peut donc indirectement contenir
du texte si celui-ci fait partie du contenu d'un de ses descendants.
La déclaration d'un élément de contenu pur détermine quels peuvent être ses enfants et dans quel ordre ils doivent apparaître. Cette
description est indépendante du contenu de ces enfants. Elle dépend uniquement des noms des enfants. Le contenu de chaque enfant
est décrit par sa propre déclaration. Une déclaration d'élément prend la forme suivante.
<!ELEMENT element regexp>
Le nom de l'élément est donné par l'identifiant element. L'expression rationnelle regexp décrit les suites autorisées d'enfants dans le
contenu de l'élément. Cette expression rationnelle est construite à partir des noms d'éléments en utilisant les opérateurs ',', '|', '?', '*' et
'+' ainsi que les parenthèses '(' et ')' pour former des groupes. Les opérateurs ',' et '|' sont binaires alors que les opérateurs '?', '*' et '+'
sont unaires et postfixés. Ils se placent juste après leur opérande, c'est-à-dire derrière le groupe auquel ils s'appliquent.

Le nom d'un élément signifie que cet élément doit apparaître dans le contenu. Les opérateurs principaux sontles deux opérateurs ',' et '|'
qui expriment la mise en séquence et le choix. Un contenu est valide pour une expression de la forme block-1, block-2 s'il est formé
d'un contenu valide pour block-1 suivi d'un contenu valide pour block-2. Un contenu est valide pour une expression de la forme block-1
| block-2 s'il est formé d'un contenu valide pour block-1 ou d'un contenu valide pour block-2. Les trois opérateurs '?', '*' et '+'
permettent d'exprimer des répétitions.
27

Un contenu est valide pour une expression de la forme block? s'il est vide ou formé d'un contenu valide pour block. Un contenu est valide
pour une expression de la forme block* (respectivement block+) s'il est formé d'une suite éventuellement vide (respectivement suite non
vide) de contenus valides pour block. La signification des cinq opérateurs est récapitulée par la table suivante.

Opérateur Signification

, Mise en séquence

| Choix

? 0 ou 1 occurrence

* Répétition d'un nombre quelconque


d'occurrences

+ Répétition d'un nombre non nul d'occurrences

Tableau 6.1. Opérateurs des DTD


28

Ces définitions sont illustrées par les exemples suivants.


<!ELEMENT elem (elem1, elem2, elem3)>
L'élément elem doit contenir un élément elem1, un élément elem2 puis un élément elem3 dans cet ordre.
<!ELEMENT elem (elem1 | elem2 | elem3)>
L'élément elem doit contenir un seul des éléments elem1, elem2 ou elem3.
<!ELEMENT elem (elem1, elem2?, elem3)>
L'élément elem doit contenir un élément elem1, un ou zéro élément elem2 puis un élément elem3 dans cet ordre.
<!ELEMENT elem (elem1, elem2*, elem3)>
L'élément elem doit contenir un élément elem1, une suite éventuellement vide d'éléments elem2 et un élément elem3 dans cet ordre.
<!ELEMENT elem (elem1, (elem2 | elem4), elem3)>
L'élément elem doit contenir un élément elem1, un élément elem2 ou un élément elem4 puis un élément elem3 dans cet ordre.
<!ELEMENT elem (elem1, elem2, elem3)*>
L'élément elem doit contenir une suite d'éléments elem1, elem2, elem3, elem1, elem2, ... jusqu'à un élément elem3.
<!ELEMENT elem (elem1 | elem2 | elem3)*>
L'élément elem doit contenir une suite quelconque d'éléments elem1, elem2 ou elem3.
<!ELEMENT elem (elem1 | elem2 | elem3)+>
L'élément elem doit contenir une suite non vide d'éléments elem1, elem2 ou elem3.
29

6.1.1. Caractères d'espacement


La prise en compte des caractères d'espacement [Section 2.2.2] lors de validation d'un élément de contenu pur dépend du caractère
interne ou externe de la DTD et de la valeur de l'attribut standalone de l'entête. Bien que le contenu d'un élément soit pur, il est,
néanmoins, possible d'insérer des caractères d'espacement entre ses enfants. La validation ignore ces caractères lorsque la DTD est
interne ou lorsque la valeur de l'attribut standalone est no. Ce traitement particulier rend possible l'indentation du document. Si la DTD
est externe et que la valeur de l'attribut standalone est yes, la validation devient stricte et elle n'autorise aucun caractère d'espacement
dans un contenu pur.
La DTD suivante déclare un élément list de contenu pur. Il contient une suite non vide d'éléments item contenant chacun du texte.
<!-- Fichier "standalone.dtd" -->
<!ELEMENT list (item)+>
<!ELEMENT item (#PCDATA)>
Le document suivant est valide pour la DTD précédente car la valeur de l'attribut standalone de l'entête est no. Si cette valeur était yes, le
document ne serait plus valide car l'élément list contient des caractères d'espacement entre ses enfants item.
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
<!DOCTYPE list SYSTEM "standalone.dtd">
<list>
<item>Item 1</item>
<item>Item 2</item>
</list>
30

6.1.2. Contenu déterministe


Afin de simplifier la validation de documents, les expressions rationnelles qui décrivent les contenus purs des éléments doivent être
déterministes. Cette contrainte signifie qu'en cours d'analyse du contenu, le nom d'un élément ne peut apparaître que sur une seule
branche de l'expression. Un exemple typique d'expression ne respectant pas cette règle est la suivante.

<!ELEMENT item ((item1, item2) | (item1, item3))>

Lors de l'analyse du contenu de l'élément item, le validateur ne peut pas déterminer en lisant l'élément item1 si celui-ci provient de la
première alternative (item1, item2) ou de la seconde alternative (item1, item3).
L'expression précédente peut, cependant, être remplacée par l'expression équivalente suivante qui a l'avantage d'être déterministe.

<!ELEMENT item (item1, (item2 | item3))>

Le non-déterminisme d'une expression peut aussi provenir d'un des deux opérateurs '?' ou '*'. L'expression (item1?, item1) n'est pas
déterministe car il n'est pas possible de déterminer immédiatement si un élément item1 correspond à la première ou à la seconde
occurrence de item1 dans l'expression. Cette expression est équivalente à l'expression (item1, item1?) qui est déterministe. Il existe
toutefois des expressions sans expression déterministe équivalente comme l'expression suivante.
<!ELEMENT item ((item1, item2)*, item1)>
31

6.2. Contenu textuel


La déclaration de la forme suivante indique qu'un élément peut uniquement contenir du texte. Ce texte est formé de caractères, d'entités
qui seront remplacées au moment du traitement et de sections littérales.
<!ELEMENT element (#PCDATA)>
Dans l'exemple suivant, l'élément text est de type #PCDATA.
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE texts [
<!ELEMENT texts (text)*>
<!ELEMENT text (#PCDATA)>
]>
<texts>
<text>Du texte simple</text>
<text>Une <![CDATA[ Section CDATA avec < et > ]]></text>
<text>Des entités &lt; et &gt;</text>
</texts>
32

6.3. Contenu mixte


La déclaration de la forme suivante indique qu'un élément peut uniquement contenir du texte et les éléments element1, ..., elementN. C'est
la seule façon d'avoir un contenu mixte avec du texte et des éléments. Il n'y a aucun contrôle sur le nombre d'occurrences de chacun des
éléments et sur leur ordre d'apparition dans le contenu de l'élément ainsi déclaré. Dans une telle déclaration, le mot clé #PCDATA doit
apparaître en premier avant tous les noms des éléments.
<!ELEMENT element (#PCDATA | element1 | ... | elementN)*>
Dans l'exemple suivant, l'élément book possède un contenu mixte. Il peut contenir du texte et des éléments em et cite en nombre
quelconque et dans n'importe quel ordre.
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE book [
<!ELEMENT book (#PCDATA | em | cite)*>
<!ELEMENT em (#PCDATA)>
<!ELEMENT cite (#PCDATA)>
]>
<book>
Du <em>texte</em>, une <cite>citation</cite> et encore du <em>texte</em>.
</book>
33

6.4. Contenu vide

La déclaration suivante indique que le contenu de l'élément element est nécessairement vide. Cet élément peut uniquement avoir des
attributs. Les éléments vides sont souvent utilisés pour des liens entre éléments.
<!ELEMENT element EMPTY>
Des exemples d'utilisation d'éléments de contenu vide sont donnés à la section traitant des attributs de type ID, IDREF et IDREFS.
<!ELEMENT ref EMPTY>
<!ATTLIST ref idref IDREF #REQUIRED>
Dans un souci de portabilité, il est conseillé de contracter les balises ouvrante et fermante lorsqu'un élément est déclaré de contenu vide
et de le faire uniquement dans ce cas.
34

6.5. Contenu libre*

La déclaration suivante n'impose aucune contrainte sur le contenu de l'élément element. En revanche, ce contenu doit, bien
entendu, être bien formé et les éléments contenus doivent également être déclarés. Ce type de déclarations permet de
déclarer des éléments dans une DTD en cours de mise au point afin de procéder à des essais de validation.
En revanche, ces déclarations sont déconseillées dans une DTD terminée car elles conduisent à des modèles de
documents trop laxistes.
<!ELEMENT element ANY>
35

7. Déclaration d'attribut

Pour qu'un document soit valide, tout attribut présent dans la balise ouvrante d'un élément doit être déclaré. La déclaration d'attribut
prend la forme générale suivante où attribut est le nom de l'attribut et element le nom de l'élément auquel il appartient. Cette déclaration
comprend également le type type et la valeur par défaut efault de l'attribut. Le nom de l'attribut doit être un nom XML.
<!ATTLIST element attribut type default>
Il est possible de déclarer simultanément plusieurs attributs pour un même élément. Cette déclaration prend alors la forme suivante où
l'indentation est bien sûr facultative.
<!ATTLIST element attribut1 type1 default1
attribut2 type2 default2
...
attributN typeN defaultN>
36

7.1. Types des attributs


Le type d'un attribut détermine quelles sont ses valeurs possibles. Les DTD proposent uniquement un choix fini
de types pour les attributs. Le type doit en effet être pris dans la liste suivante. Les types les plus utilisés sont CDATA, ID et IDREF.
CDATA
Ce type est le plus général. Il n'impose aucune contrainte à la valeur de l'attribut. Celle-ci peut être une chaîne quelconque de caractères.
(value-1 | value-2 | ... | value-N)
La valeur de l'attribut doit être un des jetons [Section 2.2.3] value-1, value-2, ... value-N. Comme ces valeurs sont des jetons, celles-ci ne
sont pas délimitées par des apostrophes ''' ou des guillemets '"'.
NMTOKEN
La valeur de l'attribut est un jeton [Section 2.2.3].
NMTOKENS
La valeur de l'attribut est une liste de jetons séparés par des espaces.
ID
La valeur de l'attribut est un nom XML [Section 2.2.3]. Un élément peut avoir un seul attribut de ce type.
IDREF
La valeur de l'attribut est une référence à un élément identifié par la valeur de son attribut de type ID.
37

IDREFS
La valeur de l'attribut est une liste de références séparées par des espaces.
NOTATION
La valeur de l'attribut est une notation
ENTITY
La valeur de l'attribut une entité externe non XML
ENTITIES
La valeur de l'attribut une liste d'entités externes non XML
Le type le plus général est CDATA puisque toutes les valeurs correctes d'un point de vue syntaxique sont permises. Cet type est très
souvent utilisé car il est approprié dès qu'il n'y a aucune contrainte sur la valeur de l'attribut.

Les types NMTOKEN et NMTOKENS imposent respectivement que la valeur de l'attribut soit un jeton ou une suite de jetons séparés par
des espaces. Il est aussi possible d'imposer que la valeur de l'attribut soit dans une liste fixe de jetons. Il est impossible, avec une DTD, de
restreindre les valeurs d'un attribut à une liste fixe de valeurs qui ne sont pas des jetons.

L'utilisation des trois types NOTATION, ENTITY et ENTITIES est réservée à l'usage des entités externes non XML et elle n'est pas détaillée
dans cet ouvrage. L'utilisation des trois types ID, IDREF et IDREFS est développée à la section suivante.
38

Il est fréquent qu'il existe des liens entre les données d'un document XML. Il peut s'agir, par exemple, de références à d'autres parties du
document. Les attributs de types ID, IDREF et IDREFS s'utilisent conjointement pour matérialiser ces liens au sein d'un document. Un
attribut de type ID permet d'identifier de façon unique un élément du document. Les éléments ainsi identifiés peuvent alors être référencés
par d'autres éléments grâce aux attributs de types IDREF et IDREFS. Ces attributs créent ainsi des liens entre des éléments ayant les
attributs de types IDREF ou IDREFS et des éléments ayant les attributs de type ID. Ce mécanisme permet uniquement de créer des liens
entre des éléments d'un même document. La norme XLink généralise ce mécanisme. Elle permet de créer des liens entre deux, voire même
plus de fragments de documents XML provenant éventuellement de documents différents.

La valeur d'un attribut de type ID doit être un nom XML. La valeur de cet attribut doit être unique dans tout le document. Ceci signifie qu'un
autre attribut de type ID d'un autre élément ne peut pas avoir la même valeur pour que le document soit valide. Un élément ne peut avoir
qu'un seul attribut de type ID.

Les attributs de type ID sont utilisés par la fonction XPath id() qui retourne les nœuds identifiés par la valeur de leur attribut de type ID.
39

La valeur d'un attribut de type IDREF doit être un nom XML. Ce nom doit, en outre, être la valeur d'un attribut de type ID d'un (autre) élément
pour que le document soit valide. La valeur d'un attribut de type IDREFS doit être une suite de noms séparés par des espaces. Chacun de
ces noms doit, en outre, être la valeur d'un attribut de type ID d'un élément pour que le document soit valide.

Le document suivant illustre l'utilisation des attributs de type ID, IDREF et IDREFS qui est faite par DocBook pour les références internes.
Son contenu est scindé en sections délimitées par les éléments section. Chacun de ces éléments a un attribut id de type ID. Le contenu des
éléments section est constitué de texte et d'éléments ref et refs ayant respectivement un attribut idref de type IDREF et un attribut idrefs de
type IDREFS. Ces éléments permettent, dans le contenu d'une section, de référencer une (par ref) ou plusieurs (par refs) autres sections. Il
faut remarquer que les éléments ref et refs n'ont jamais de contenu. Ils sont déclarés vides en utilisant le mot clé EMPTY. Il appartient à
l'application qui génère le document final d'ajouter du contenu qui peut être, par exemple, le numéro ou le titre de la section référencée.
40

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


<!DOCTYPE book [
<!ELEMENT book (section)*>
<!ELEMENT section (#PCDATA | ref | refs)*>
<!ATTLIST section id ID #IMPLIED>
<!ELEMENT ref EMPTY>
<!ATTLIST ref idref IDREF #REQUIRED>
<!ELEMENT refs EMPTY>
<!ATTLIST refs idrefs IDREFS #REQUIRED>
]>
<book>
<section id="sec0">Une référence <ref idref="sec1"/></section>
<section id="sec1">Des références <refs idrefs="sec0 sec2"/></section>
<section id="sec2">Section sans référence</section>
<section id="sec3">Une auto-référence <refs idrefs="sec3"/></section>
</book>
41

Les attributs de type ID et IDREF permettent également de structurer un document. Si l'adresse et d'autres informations sont ajoutées à
l'éditeur dans le document bibliography.xml, celles-ci sont recopiées dans chaque livre publié par l'éditeur. Cette duplication de
l'information est bien sûr très mauvaise. Une meilleure approche consiste à scinder la bibliographie en deux parties. Une première partie
contient les livres et une seconde partie les éditeurs avec les informations associées. Ensuite, chaque livre se contente d'avoir une
référence sur son éditeur. Un attribut id de type ID est ajouté à chaque élément publisher de la seconde partie. Chaque élément
publisher contenu dans un élément book est remplacé par un élément published ayant un attribut by de type IDREF.
42

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


<bibliography>
<books>
<book key="Michard01" lang="fr">
<title>XML langage et appplications</title>
<author>Alain Michard</author>
<year>2001</year>
<isbn>2-212-09206-7</isbn>
<url>http://www.editions-eyrolles/livres/michard/</url>
<published by="id2680397"/>
</book>
<book key="Marchal00" lang="en">
<title>XML by Example</title>
<author>Benoît Marchal</author>
<year>2000</year>
<isbn>0-7897-2242-9</isbn>
<published by="id2680427"/>
</book>
...
</books>
43

<publishers>
<publisher id="id2680397">
<name>Eyrolles</name>
<address>Paris</address>
</publisher>
<publisher id="id2680427">
<name>Macmillan Computer Publishing</name>
<address>New York</address>
</publisher>
...
</publishers>
</bibliography>

Beaucoup d'applications ne prennent pas en compte la DTD pour traiter un document. Il leur est alors impossible de savoir quels attributs
sont de type ID, IDREF ou IDREFS. Elles utilisent souvent la convention qu'un attribut de nom id est implicitement de type ID. Une meilleure
solution consiste à utiliser l'attribut xml:id qui est toujours de type ID (de type xsd:ID en fait).
44

7.3. Valeur par défaut


Chaque déclaration d'attribut précise une valeur par défaut pour celui-ci. Cette valeur par défaut peut prendre une des quatre formes
suivantes.
"value" ou 'value'
La valeur value est une chaîne quelconque de caractères délimitée par des apostrophes ''' ou des guillemets '"'. Si l'attribut est absent
pour un élément du document, sa valeur est implicitement la chaîne value. Cette valeur doit, bien sûr, être du type donné à l'attribut.
#IMPLIED
L'attribut est optionnel et il n'a pas de valeur par défaut. Si l'attribut est absent, il n'a pas de valeur.
#REQUIRED
L'attribut est obligatoire et il n'a pas de valeur par défaut.
#FIXED "value" ou #FIXED 'value'
La valeur value est une chaîne quelconque de caractères délimitée par des apostrophes ''' ou des guillemets '"'. La valeur de l'attribut est
fixée à la valeur value donnée. Si l'attribut est absent, sa valeur est implicitement value. Si l'attribut est présent, sa valeur doit être value
pour que le document soit valide. Cette valeur doit, bien sûr, être du type donné à l'attribut.

Beaucoup d'applications ne prennent pas en compte la DTD pour traiter un document XML. Ce comportement pose problème avec les
valeurs par défaut et les valeurs fixes (utilisation de #FIXED) des attributs. Si l'attribut est absent pour un élément du document, l'application
va considérer que l'attribut n'a pas de valeur bien que la DTD déclare une valeur par défaut. L'utilisation des valeurs par défaut est donc à
éviter pour une portabilité maximale.
45

7.4. Exemples
Voici quelques exemples de déclarations d'attributs avec, pour chacune d'entre elles, des valeurs valides et non valides pour l'attribut.
<!ATTLIST tag meta CDATA "default">
La valeur de l'attribut meta peut être une chaîne quelconque et sa valeur par défaut est la chaîne default Les exemples illustrent
l'utilisation des entités prédéfinies pour inclure des caractères spéciaux dans les valeurs d'attribut.
46

<!ATTLIST book lang (fr | en) "fr">


La valeur de l'attribut lang peut être soit le jeton fr soit le jeton en et sa valeur par défaut est le jeton fr.
47

<!ATTLIST book name NMTOKEN #IMPLIED>


L'attribut name est optionnel et sa valeur doit être un jeton. Il n'a pas de valeur par défaut.
48

<!ATTLIST entry id ID #REQUIRED>


L'attribut id est obligatoire et sa valeur doit être un nom unique. Il n'a pas de valeur par défaut.
49

<!ATTLIST xref ref IDREF #REQUIRED>


L'attribut ref est obligatoire et sa valeur doit être un nom XML. Pour que le document soit valide, ce nom
doit être la valeur d'un attribut de type ID d'un (autre) élément. Cet attribut n'a pas de valeur par défaut.
50

<!ATTLIST xrefs refs IDREFS #REQUIRED>


L'attribut refs est obligatoire et sa valeur doit être une suite de noms XML séparés par des espaces. Pour que le document soit
valide, chacun des noms de la liste doit être la valeur d'un attribut de type ID d'un (autre) élément. Il n'a pas de valeur par défaut.
51

<!ATTLIST rule style CDATA #FIXED "free">


La valeur de l'attribut style de l'élément rule est fixée à la valeur free.
52

8. Outils de validation
Il existe plusieurs outils permettant de valider un document XML par rapport à une DTD. Il existe d'abord des sites WEB dont l'avantage est
une interface conviviale. L'utilisateur peut fournir son document par un simple copier/coller ou en le téléchargeant. Comme la validation est
réalisée sur une machine distante, la DTD doit être, soit accessible via une URL, soit directement incluse dans document.
• Page de validation du W3C [http://validator.w3.org/]
• Page de validation du Scholarly Technology Group de l'université de Brown [http://www.stg.brown.edu/service/
xmlvalid/]

L'inconvénient majeur de ces sites WEB est la difficulté de les intégrer à une chaîne de traitement automatique puisqu'ils requièrent
l'intervention de l'utilisateur. Dans ce cas, il est préférable d'utiliser un logiciel comme xmllint. Avec l'option --valid, il réalise la validation du
document passé en paramètre. Avec cette option, la DTD soit être précisée par une déclaration de DTD dans le prologue du document.
Sinon, il faut donner explicitement la DTD après l'option --dtdvalid. La DTD peut être donnée par le nom d'un fichier local
ou par une URL qui permet à xmllint d'accéder à celle-ci.

Vous aimerez peut-être aussi