Copyright © 2005-2022 Yves MARCOUX; dernière modification de cette page : 2022-01-04.
INU3011 Documents structurés – Premier Tour d’horizon de XML
Index de ce texte — Index général du Tour d’horizon — Accueil du Tour d’horizon
Yves MARCOUX - EBSI - Université de Montréal
ELEMENT
(#PCDATA)
,
»|
»+
»*
»?
»EMPTY
ATTLIST
Rappelons que le langage des DTD (Document Type Definition) sert à exprimer des contraintes de forme – ou règles syntaxiques – qui doivent être respectées par certains documents XML, au-delà des règles du bien-formé. Ce langage permet à une modélisatrice de rédiger une DTD correspondant à une forme de document appropriée pour un certain contexte et/ou certaines opérations. Un document valide selon une DTD est un « contenant » qui favorise une bonne saisie de l’information et facilite son traitement.
Le langage des DTD ressemble un peu au XML bien formé, dans la mesure où une DTD se
présente concrètement comme un fichier texte (toujours en UTF-8 dans ce premier tour
d’horizon) et dans la mesure où les caractères <
et >
y
jouent aussi un rôle particulier. Il n’en demeure pas moins qu’il s’agit d’un
langage complètement différent.
Ce texte présente les principaux aspects de ce langage. Le texte Validité d’un document XML est un prérequis.
Une DTD n’est rien d’autre qu’une suite de déclarations inscrites dans
un fichier texte. Chaque déclaration est un segment contigu de caractères
consécutifs, commençant par <!
et se terminant par >
,
et qui respecte une forme particulière.
Les déclarations ne sont jamais imbriquées l’une dans l’autre, mais se suivent simplement séquentiellement.
L’ordre d’apparition des déclarations dans une DTD n’a aucune importance (sauf dans de très rares cas, qui ne sont pas couverts dans ce Premier tour d’horizon).
Notons qu’avant, entre et/ou après les déclarations, il peut y avoir des espaces blancs (espaces, sauts de ligne, tabulations, etc.) et des commentaires, qui sont simplement ignorés. Habituellement, les déclarations sont séparées entre elles par un saut de ligne ou plus, mais cette pratique vise uniquement la lisibilité de la DTD et n’est nullement obligatoire.
Les commentaires dans une DTD sont une façon très répandue de documenter un modèle XML, notamment de décrire en langue naturelle ce que l’on s’attend à retrouver dans chaque type d’élément.
Une DTD permet à une modélisatrice de formuler des contraintes (ou restrictions) sur :
Un point important du langage des DTD est que ces contraintes ne s’expriment pas par la négative (telle ou telle chose est défendue dans les documents), mais plutôt par des énoncés positifs, qui définissent ce que l’on peut ou doit retrouver dans les documents. Les contraintes exprimées ne sont jamais du genre telle chose est interdite, mais toujours du genre voici ce qu’on peut ou doit retrouver à tel ou tel endroit dans le document. Tout ce qui n’est pas explicitement permis par la DTD est refusé; c’est de cette façon que les contraintes exprimées restreignent les documents acceptés.
La modélisatrice formule les contraintes en utilisant des déclarations de deux
types : ELEMENT
et ATTLIST
. Une déclaration
ELEMENT
détermine ce que l’on peut ou doit
retrouver comme contenu des éléments d’un certain type, alors qu’une déclaration
ATTLIST
définit un attribut que l’on peut ou
doit retrouver sur les éléments d’un certain type.
La modélisatrice doit rédiger une déclaration ELEMENT
pour
chaque type d’élément dans son modèle, et une déclaration
ATTLIST
pour chaque attribut qu’il est possible de retrouver
sur chaque type d’élément du modèle.
Rappelez-vous qu’en marge de la DTD, la modélisatrice doit aussi décider du type (ou nom) d’élément à utiliser comme élément de plus haut niveau des documents, puisque cette information n’est pas explicitement présente dans la DTD. Une bonne pratique consiste à déclarer l’élément de plus haut niveau en premier dans la DTD, ou à l’identifier dans un commentaire au début de la DTD, mais cette pratique n’est ni obligatoire, ni universellement observée.
ELEMENT
Les déclarations ELEMENT
permettent de définir exactement ce que
chaque type d’élément peut avoir comme contenu. Avant de voir la forme générale,
voyons un exemple
simple qui nous permettra d’avoir une idée générale de leur
fonctionnement.
Supposons qu’on envisage de mettre sur pied un système informatisé pour compiler les absences d’élèves à certains cours dans une école. Le personnel est suffisamment « techno » pour qu’on demande aux professeurs de transmettre l’information sous forme de documents XML (par exemple par courriel, mais ce pourrait être aussi via un système en ligne). On veut donc définir un modèle XML (une DTD) correspondant aux documents qui seront remplis et transmis par les professeurs.
Commençons par le choix d’un nom d’élément pour l’élément de plus haut niveau des
documents (qui, encore une fois, ne s’exprime pas explicitement dans la DTD). On
choisit en général quelque chose de simple et direct, alors, comme il s’agit de
notifications d’absence, allons-y avec notification-d-absence
. Notez
qu’on ne peut utiliser ni l’espace ni l’apostrophe dans un nom d’élément, de sorte
que notification d’absence
n’est pas un choix possible. Notez aussi
qu’on utilise « notification » au singulier, puisque chaque document portera sur une
seule absence.
On passe maintenant aux déclarations ELEMENT
. Il s’agit de déterminer
ce que chaque type d’élément dans nos documents devra contenir. Commençons par le
type des éléments de plus haut niveau dans nos documents :
notification-d-absence
. En supposant que les seules informations
nécessaires sont la date de l’absence, le nom de l’élève et le titre du cours
manqué, on pourrait rédiger la déclaration ELEMENT
suivante :
<!ELEMENT notification-d-absence (date-de-l-absence, nom-de-l-élève, titre-du-cours-manqué)>
Cette déclaration stipule qu’à chaque fois qu’on rencontre un élément de type
notification-d-absence
, son contenu doit consister en une
séquence d’exactement trois sous-éléments : date-de-l-absence
,
nom-de-l-élève
et titre-du-cours-manqué
, dans cet ordre.
Comme nous savons que l’élément notification-d-absence
est l’élément de
plus haut niveau des documents, la déclaration se trouve à fixer la forme générale
du document comme tel. Concrètement, cela veut dire que les documents valides auront
tous la forme suivante (abstraction faite de la déclaration
DOCTYPE
) :
<notification-d-absence>
<date-de-l-absence>…</date-de-l-absence>
<nom-de-l-élève>…</nom-de-l-élève>
<titre-du-cours-manqué>…</titre-du-cours-manqué>
</notification-d-absence>
Comme nous venons d’introduire trois nouveaux types d’éléments, il faut aussi les
déclarer. Nous aurons donc besoin de trois autres déclarations ELEMENT
.
Pour la date et le titre du cours, nous choisissons de simplement faire inscrire
l’information en texte libre, sans utiliser de sous-éléments, alors nous aurons ces
deux déclarations :
<!ELEMENT date-de-l-absence (#PCDATA)>
<!ELEMENT titre-du-cours-manqué (#PCDATA)>
Ces déclarations stipulent que les éléments des types concernés doivent
toujours ne contenir que du texte et pas de sous-éléments. Concrètement,
cela veut dire que, par exemple, tout élément date-de-l-absence
rencontré dans nos documents aura forcément l’allure d’un bout de texte entouré des
balises <date-de-l-absence>
et </date-de-l-absence>
,
comme ceci :
<date-de-l-absence>2032-07-09</date-de-l-absence>
Il ne peut y avoir de sous-élément. Le type d’élément
titre-du-cours-manqué
étant déclaré de la même façon que
date-de-l-absence
, la même chose est vraie pour les éléments de type
titre-du-cours-manqué
.
Pour le nom de l’élève, pour éviter les ambiguïtés, nous choisissons de faire inscrire le prénom et le nom de famille dans deux sous-éléments distincts. Nous rédigeons donc la déclaration suivante :
<!ELEMENT nom-de-l-élève (prénom, nom-de-famille)>
qui stipule que tout élément nom-de-l-élève
doit contenir une séquence
de deux sous-éléments : prénom
et nom-de-famille
. À leur
tour, ces éléments doivent être déclarés. Comme on ne souhaite pas subdiviser
au-delà du prénom ou du nom de famille, les déclarations suivantes stipuleront que
les éléments de ces deux types ne peuvent contenir que du texte :
<!ELEMENT prénom (#PCDATA)>
<!ELEMENT nom-de-famille (#PCDATA)>
Au final, nous avons six déclarations ELEMENT
qui, ensemble, forment
notre DTD :
<!ELEMENT notification-d-absence (date-de-l-absence, nom-de-l-élève, titre-du-cours-manqué)>
<!ELEMENT date-de-l-absence (#PCDATA)>
<!ELEMENT nom-de-l-élève (prénom, nom-de-famille)>
<!ELEMENT titre-du-cours-manqué (#PCDATA)>
<!ELEMENT prénom (#PCDATA)>
<!ELEMENT nom-de-famille (#PCDATA)>
Rappelons que, même si l’ordre des déclarations peut sembler important, ce n’est pas le cas et les déclarations pourraient apparaître dans n’importe quel ordre.
Supposons que ces six déclarations sont placées dans un fichier texte accessible à
l’URL http://ecole.XYZ.org/absence.dtd
(l’extension .dtd
est celle habituellement utilisée pour une DTD, mais ce n’est pas obligatoire).
Alors, voici un exemple complet de document valide selon cette DTD :
<!DOCTYPE notification-d-absence SYSTEM "http://ecole.XYZ.org/absence.dtd">
<notification-d-absence>
<date-de-l-absence>2036-01-31</date-de-l-absence>
<nom-de-l-élève>
<prénom>Clotaire</prénom>
<nom-de-famille>Euler</nom-de-famille>
</nom-de-l-élève>
<titre-du-cours-manqué>Mathématiques 101</titre-du-cours-manqué>
</notification-d-absence>
Dès qu’un document contient un élément qui n’a pas été déclaré dans la DTD, ou dont le contenu n’est pas conforme à la déclaration de son type, le document est invalide, c’est-à-dire non valide (l’élément fautif, de même que son contenu, sont eux aussi dits invalides). Voici quelques exemples de documents bien formés, mais invalides selon notre DTD. Assurez-vous de bien comprendre en quoi chaque exemple déroge des règles exprimées dans la DTD (dans chaque cas, la partie fautive du document est mise en rouge et expliquée dans un commentaire).
<!DOCTYPE notification-d-absence SYSTEM
"http://ecole.XYZ.org/absence.dtd">
<notification-d-absence>
<date-de-l-absence>2036-01-31</date-de-l-absence>
<nom-de-l-élève>Clotaire Euler</nom-de-l-élève>
<!-- Le nom doit être subdivisé en sous-éléments prénom et nom-de-famille.
-->
<titre-du-cours-manqué>Mathématiques
101</titre-du-cours-manqué>
</notification-d-absence>
<!DOCTYPE notification-d-absence SYSTEM
"http://ecole.XYZ.org/absence.dtd">
<notification-d-absence>
<date-de-l-absence>2036-01-31</date-de-l-absence>
<nom-de-l-élève>
<prénom>Clotaire</prénom>
<nom-de-famille>Euler</nom-de-famille>
</nom-de-l-élève>
<titre-du-cours-manqué>Géographie
101</titre-du-cours-manqué>
<titre-du-cours-manqué>Mathématiques
101</titre-du-cours-manqué>
<!-- Il ne peut y avoir qu’un seul
sous-élément titre-de-cours-manqué.
-->
</notification-d-absence>
<!DOCTYPE notification-d-absence SYSTEM
"http://ecole.XYZ.org/absence.dtd">
<notification-d-absence>
<date-de-l-absence>2036-01-31</date-de-l-absence>
<nom-de-l-élève>
<nom-de-famille>Euler</nom-de-famille>
<prénom>Clotaire</prénom>
<!--
Les sous-éléments prénom et nom-de-famille n’apparaissent pas dans le bon ordre.
-->
</nom-de-l-élève>
<titre-du-cours-manqué>Mathématiques
101</titre-du-cours-manqué>
</notification-d-absence>
<!DOCTYPE notification-d-absence SYSTEM
"http://ecole.XYZ.org/absence.dtd">
<notification-d-absence>
<!-- Il manque le sous-élément date-de-l-absence
-->
<nom-de-l-élève>
<prénom>Clotaire</prénom>
<nom-de-famille>Euler</nom-de-famille>
</nom-de-l-élève>
<titre-du-cours-manqué>Mathématiques
101</titre-du-cours-manqué>
</notification-d-absence>
<!DOCTYPE notification-d-absence SYSTEM
"http://ecole.XYZ.org/absence.dtd">
<notification-d-absence>
<date-de-l-absence>2036-01-31</date-de-l-absence>
<nom-de-l-élève>
<prénom>Clotaire</prénom>
<nom-de-famille>Euler</nom-de-famille>
</nom-de-l-élève>
<titre-du-cours-manqué>Mathématiques
<niveau>101</niveau></titre-du-cours-manqué>
<!-- L’élément titre-du-cours-manqué ne peut pas contenir de
sous-élément. De plus, le type d’élément "niveau" n’est pas déclaré.
-->
</notification-d-absence>
Comme on peut le constater, la DTD restreint de façon très stricte la forme que peuvent prendre les documents pour être valides.
La forme générale d’une déclaration
ELEMENT
est :
<!ELEMENT type-d-élément modèle-de-contenu >
Tout ce qui suit le type (= nom) d’élément constitue donc ce qu’on appelle le
modèle de contenu. Un modèle de contenu permet d’exprimer la forme
générale que peut avoir le contenu d’un élément. L’effet de la déclaration est de
stipuler que tout élément de type type-d-élément
doit, pour
être valide, avoir un contenu conforme au modèle de contenu donné.
Dans le contexte d’une DTD donnée, quand on parle du « modèle de contenu d’un
élément », on veut dire le modèle de contenu figurant dans la déclaration
ELEMENT
de ce type d’élément.
Un document comportant une déclaration DOCTYPE
(donc, qui pointe à une DTD) est valide seulement si chaque élément (y compris
l’élément-document) est déclaré et a un contenu conforme à son modèle de contenu. Si
un élément n’a pas été déclaré, ou a un contenu non conforme à son modèle de
contenu, alors l’élément lui-même, son contenu et le document dans son entier sont
tous les trois dits invalides.
Afin de créer un document valide – c’est-à-dire respectant les contraintes additionnelles définies par la modélisatrice dans sa DTD, un auteur doit donc s’assurer de placer dans chaque élément (y compris l’élément-document) un contenu conforme au modèle de contenu de cet élément.
Un contenu qui est conforme à un modèle de contenu donné est dit accepté par ce modèle de contenu. Un contenu qui n’est pas conforme au modèle de contenu est dit refusé par lui.
Ainsi, dans notre exemple ci-dessus, on dira le modèle de contenu (prénom,
nom-de-famille)
refuse le contenu suivant :
REFUSÉ :
<nom-de-famille>Jacques</nom-de-famille><prénom>Claude</prénom>
puisque le nom de famille vient avant le prénom, mais accepte celui-ci :
<prénom>Claude</prénom><nom-de-famille>Jacques</nom-de-famille>
Par extension, on dira qu’un type d’élément accepte ou refuse un contenu si son modèle de contenu l’accepte ou le refuse.
Un modèle de contenu est constitué de noms d’élément, de certains mots-clés fixes
(comme par exemple #PCDATA
), de parenthèses et d’opérateurs
(comme par exemple la virgule ,
). Les différents noms d’élément,
mots-clés, parenthèses et opérateurs doivent être combinés selon une certaine
syntaxe et c’est pourquoi on parle du langage des modèles de contenu. Comme
ce langage est utilisé à l’intérieur des déclarations ELEMENT
qui,
elles-mêmes font partie du langage des DTD, on peut dire que le langage des modèles
de contenu est un sous-langage de celui des DTD.
À part le modèle de contenu EMPTY
(défini plus
loin), qui s’écrit sans parenthèses, un modèle de contenu s’écrit toujours
entre parenthèses ( )
. Le modèle de contenu
ANY
s’écrit aussi sans parenthèses, mais n’est pas traité dans ce
texte.
(#PCDATA)
Nous avons déjà vu dans notre exemple le modèle de contenu
(#PCDATA)
. Ce modèle de
contenu accepte n’importe quel contenu dépourvu de sous-élément, donc constitué de
texte seulement. L’acronyme PCDATA
est un
héritage de SGML et signifie Parsed Character Data. Sans le « # »,
PCDATA
serait incorrectement traité comme un nom
d’élément.
Le contenu vide est accepté par (#PCDATA)
. Il n’y a donc aucun moyen
en XML d’obliger la saisie d’un texte non vide dans un élément. C’est une lacune importante qui, pour plusieurs, justifie le
recours à des mécanismes de restrictions syntaxiques plus puissants que les DTD,
par exemple les schémas XML du W3C. Nous en parlerons en
classe.
Les autres formes de modèles de contenu couvertes dans ce texte utilisent toutes un opérateur. Il y a deux types d’opérateurs : les opérateurs de liaison et les opérateurs d’occurrence. Les opérateurs de liaison sont :
,
|
Les opérateurs d’occurrence sont :
+
*
?
Les signes utilisés pour représenter les opérateurs (, | ? * +
) sont
parfois appelés des particules.
Nous présentons d’abord ci-dessous les opérateurs dans leurs utilisations et combinaisons les plus courantes. Nous dirons ensuite quelques mots sur leur utilisation en général.
,
»La forme de base de la séquence est :
(élément1, élément2)
où élément1
et élément2
sont deux types
d’éléments déclarés ailleurs dans la DTD. Ce modèle de contenu n’accepte comme
contenu que les suites d’exactement deux éléments, de types
élément1
et élément2
, dans
cet ordre. Ainsi, dans le contexte de notre exemple, comme nous avons vu,
le modèle de contenu :
(prénom, nom-de-famille)
accepte ce contenu :
<prénom>Claude</prénom><nom-de-famille>Jacques</nom-de-famille>
mais refuse celui-ci :
REFUSÉ :
<nom-de-famille>Jacques</nom-de-famille><prénom>Claude</prénom>
Notons qu’avant, entre et/ou après les éléments, il peut y avoir des espaces blancs (espaces, sauts de ligne, tabulations, etc.), mais aucun caractère non blanc. Il peut également y avoir des commentaires. Par exemple, ces contenus seraient aussi acceptés :
<prénom>Gonzague</prénom>⤶
<nom-de-famille>Saint
Bris</nom-de-famille>
<prénom>Gonzague</prénom>⤶
¤¤<!-- Vérifier si le nom de famille prend un trait d’union !
-->⤶
<nom-de-famille>Saint Bris</nom-de-famille>
mais pas celui-ci :
REFUSÉ :
<prénom>Gonzague</prénom> dit de
<nom-de-famille>Saint Bris</nom-de-famille>
Comme nous avons vu précédemment dans notre exemple, il est possible de lier plus
de deux éléments avec la séquence, en utilisant plusieurs « ,
». Ainsi,
le modèle de contenu :
(Adresse, Téléphone, Courriel)
n’accepte que les suites d’exactement trois éléments Adresse
,
Téléphone
et Courriel
, dans cet ordre, par exemple :
<Adresse>…</Adresse>
<Téléphone>…</Téléphone>
<Courriel>…</Courriel>
Il faudrait bien sûr que ces types d’élément soient déclarés ailleurs dans la DTD,
via autant de déclarations ELEMENT
, et que les contenus que nous avons
représentés par « … » soient conformes à leur modèle de contenu respectif.
Note : Dans le reste de ce texte,
les points de suspension « … » symbolisent un
contenu accepté par le modèle de contenu du type d’élément concerné. On suppose ce
type d’élément dûment déclaré par une déclaration ELEMENT
appropriée.
Notons qu’il est possible pour un même type d’élément de se retrouver plusieurs fois dans une séquence. Ainsi, le modèle de contenu suivant est tout à fait plausible :
(Adresse, Téléphone, Téléphone, Courriel)
Ce modèle de contenu pourrait, par exemple, être approprié pour un type d’élément
appelé Coordonnées
.
|
»La forme de base du choix est :
(élément1 | élément2)
où élément1
et élément2
sont deux types
d’éléments déclarés ailleurs dans la DTD. Ce modèle de contenu n’accepte comme
contenu qu’un seul sous-élément, qui peut être soit de type
élément1
ou élément2
.
L’opérateur de choix ne figurait pas dans notre exemple précédent de DTD, mais voici un exemple d’utilisation :
<!ELEMENT requête (abonnement | désabonnement)>
Avec cette déclaration, tout élément requête
doit contenir
exactement un des deux sous-éléments abonnement
et
désabonnement
. Ainsi :
<abonnement>…</abonnement>
et
<désabonnement>…</désabonnement>
seraient acceptés comme contenu de requête
, mais tout autre contenu
serait refusé.
Tout comme avec la séquence, il est possible de lier plus de deux éléments avec le
choix, en utilisant plusieurs « |
», comme dans :
(abonnement | désabonnement | plainte)
Les contenus acceptés sont toujours un seul sous-élément, mais il y a un plus grand nombre de « candidats » parmi lesquels choisir.
+
»Il est parfois souhaitable de permettre à un élément de contenir plusieurs éléments
du même type. Prenons l’exemple des descripteurs dans une notice bibliographique. On
sait qu’en général, une notice bibliographique peut contenir plusieurs descripteurs.
Un des choix qui s’offrent à la modélisatrice est de définir un seul élément
descripteurs
et de faire inscrire par les auteurs des notices tous
les descripteurs dans cet unique élément. Ce qui donnerait quelque chose comme :
<descripteurs>temps de fêtes, neige, messe de minuit</descripteurs>
La déclaration appropriée pour descripteurs
serait alors :
<!ELEMENT descripteurs (#PCDATA)>
Il faudrait évidemment décider d’un caractère séparateur à inscrire entre les descripteurs (dans notre exemple, la virgule) et aviser les auteurs de notices qu’ils doivent respecter cette règle d’écriture.
C’est une possibilité. Cependant, en termes de facilité de traitement de l’information, il est préférable que chaque descripteur soit balisé séparément. Si on transpose en termes de formulaire, c’est un peu comme si chaque descripteur pouvait être écrit sur sa propre ligne. On imagine facilement qu’il est plus facile de transcrire des descripteurs inscrits à raison d’un par ligne que des descripteurs entassés sur une même ligne, même séparés par une virgule.
Ce que la modélisatrice voudrait permettre est d’écrire quelque chose comme :
<descripteurs>
<descripteur>temps de fêtes</descripteur>
<descripteur>neige</descripteur>
<descripteur>messe de minuit</descripteur>
</descripteurs>
C’est exactement ce que l’opérateur répétable « + » lui permet de faire. La déclaration :
<!ELEMENT descripteurs (descripteur+)>
permettra aux auteurs d’inscrire un nombre arbitraire de sous-éléments
descripteur
– mais au minimum un – comme contenu d’un élément
descripteurs
. Il faudra bien sûr déclarer aussi
descripteur
:
<!ELEMENT descripteur (#PCDATA)>
*
»L’opérateur facultatif-et-répétable
*
fonctionne exactement comme répétable, mais permet
d’inscrire l’élément répétable zéro fois. Autrement dit, l’élément qui
contient l’élément répétable peut être laissé vide. Ainsi, avec la déclaration
suivante :
<!ELEMENT descripteurs (descripteur*)>
les auteurs peuvent encore inscrire un nombre arbitraire de sous-éléments
descripteur
dans un élément descripteurs
(comme avec
répétable), mais ils peuvent également laisser l’élément
descripteurs
vide, comme ceci :
<descripteurs></descripteurs>
ce que les auteurs pourraient d’ailleurs aussi écrire comme ceci :
<descripteurs/>
?
»Quant à lui, l’opérateur facultatif
« ?
» fonctionne un peu comme facultatif-et-répétable, mais
accepte au plus une occurrence de l’élément auquel il s’applique, lequel,
de ce fait, n’est plus répétable. Autrement dit, l’élément est là (une seule fois)
ou n’est pas là.
L’utilisation de loin la plus courante de cet opérateur est en combinaison avec la séquence. Il sert alors à indiquer qu’un des éléments d’une séquence est facultatif, c’est-à-dire qu’il peut être omis.
Pour illustrer cette utilisation, nous allons reprendre l’exemple des notifications
d’absence. Imaginons que l’école souhaite permettre aux professeurs d’inscrire dans
une notification le motif de l’absence, lorsqu’il est connu (par exemple,
lorsque l’élève a avisé par avance le professeur de son absence). La modélisatrice
doit donc permettre la saisie d’un motif, mais ne doit pas l’obliger. Pour ce faire,
elle ajoutera un élément à la structure globale d’une notification, mais le rendra
facultatif en lui appliquant l’opérateur « ?
». Voici ce que
cela donne :
<!ELEMENT notification-d-absence (date-de-l-absence, nom-de-l-élève, titre-du-cours-manqué, motif?)>
Avec ce modèle de contenu, les professeurs peuvent ajouter ou non un sous-élément
motif
après le titre-du-cours-manqué
. Le type d’élément
motif
pourrait être déclaré comme suit :
<!ELEMENT motif (#PCDATA)>
Nous avons ajouté l’élément facultatif à la fin de la séquence, mais un élément facultatif peut se trouver n’importe où dans une séquence. Ainsi, techniquement, nous aurions pu l’ajouter au tout début de la séquence :
<!ELEMENT notification-d-absence (motif?, date-de-l-absence, nom-de-l-élève, titre-du-cours-manqué)>
ou au milieu :
<!ELEMENT notification-d-absence (date-de-l-absence, nom-de-l-élève, motif?, titre-du-cours-manqué)>
Il nous semblait plus naturel de l’ajouter à la fin.
La combinaison d’opérateurs que nous venons de voir
(séquence « ,
» et facultatif « ?
») n’est qu’une
des possibilités. En fait, les opérateurs peuvent être combinés sans restriction,
« à l’infini », comme les opérations d’addition, de soustraction, de multiplication
et de division peuvent l’être en arithmétique. Plus précisément :
Règle de combinaison
Dans n’importe quel modèle de contenu correct selon les règles vues jusqu’ici, si on remplace un nom d’élément par un autre modèle de contenu correct1, on en obtient un autre, tout aussi correct.
Un exemple clarifiera le processus. Prenons le modèle de contenu suivant, donné en exemple précédemment :
(Adresse, Téléphone, Téléphone, Courriel)
La règle de combinaison dit que l’on peut remplacer n’importe quel des
quatre noms d’éléments par un autre modèle de contenu correct. Supposons qu’on
remplace le deuxième Téléphone
par :
(Fax | Avertisseur)
on obtient :
(Adresse, Téléphone, (Fax | Avertisseur), Courriel)
La règle de combinaison nous dit que ce résultat est aussi un modèle de contenu correct.
Évidemment, le modèle de contenu obtenu n’accepte pas les mêmes contenus que les modèles de départ. Dans notre exemple, le modèle obtenu accepte les contenus des deux formes suivantes :
<Adresse>…</Adresse>
<Téléphone>…</Téléphone>
<Fax>…</Fax>
<Courriel>…</Courriel>
et :
<Adresse>…</Adresse>
<Téléphone>…</Téléphone>
<Avertisseur>…</Avertisseur>
<Courriel>…</Courriel>
1Une petite exception
La seule exception à la règle de combinaison est que (#PCDATA)
ne peut
pas toujours être utilisé comme modèle de remplacement. Ainsi, à partir de :
(A, B)
si on remplace le A
par (#PCDATA)
, on obtient :
((#PCDATA), B)
qui n’est pas un modèle de contenu correct, bien que les deux modèles de
départ le soient. Nous verrons à la section suivante la façon
particulière de combiner (#PCDATA)
avec d’autres éléments.
Combinaisons courantes
Deux des combinaisons les plus courantes sont :
choix « | » et répétable « + »
et :
choix « | » et facultatif-et-répétable «
*
»
Il vaut la peine d’en dire quelques mots.
On obtient une combinaison de choix « | » et répétable « + » en appliquant la règle de combinaison à partir de :
(e+)
et de n’importe quel modèle utilisant le choix, par exemple :
(A | B | C)
En remplaçant le e
du premier modèle par le second modèle, on
obtient :
((A | B | C)+)
Incidemment, il est permis dans ce cas d’omettre les parenthèses extérieures. On peut donc récrire le modèle résultant ainsi :
(A | B | C)+
Pour comprendre quels contenus ce nouveau modèle accepte, il faut réaliser que
ce qui est répétable, c’est le choix entre les trois éléments.
Pour construire adéquatement un contenu accepté par ce modèle, l’auteur d’un
document fera donc une série de choix successifs (aussi nombreux qu’il le veut)
entre A
, B
et C
.
Les contenus acceptés sont donc n’importe quelle succession d’éléments
A
ou B
ou C
,
dans n’importe quel ordre et en n’importe quelle quantité. Les contenus
suivants (affichés un par ligne) sont donc tous des exemples de contenus
acceptés :
<A>…</A>
<B>…</B>
<C>…</C>
<C>…</C> <A>…</A> <A>…</A> <C>…</C>
<C>…</C> <B>…</B> <B>…</B> <B>…</B> <A>…</A>
La combinaison choix « | » et facultatif-et-répétable « *
»
est tout à fait similaire, sauf que le contenu vide est aussi accepté.
Jusqu’ici, les modèles de contenu que nous avons vus acceptent soit du texte, soit
des sous-éléments, mais pas un mélange de sous-éléments et de texte non
blanc. En effet, à part (#PCDATA)
, qui n’accepte que du
texte, tous les autres modèles de contenu vus jusqu’ici n’acceptent que des
sous-éléments; ce peut être 0, 1 ou un nombre arbitraire de sous-éléments, mais il
ne s’agit toujours que de sous-éléments. À part des commentaires et d’éventuels
espaces blancs (espaces, sauts de ligne, tabulations, etc.) avant, après et/ou entre
les éléments, aucun texte non blanc n’est accepté par ces modèles de contenu.
Pourtant, en XML bien formé, il est tout à fait possible pour un élément de contenir à la fois du texte non blanc et des sous-éléments. C’est ce qu’on appelle un contenu mixte. Rappelez-vous l’exemple suivant tiré du texte Qu’est-ce qu’un document XML ? :
<liste>Voici deux items:<item>1</item><item>2</item></liste>
qui donne ceci en navigateur :
L’élément liste
contient directement deux sous-éléments
item
, mais également le bout de texte "Voici deux
items:"
. L’élément a un contenu mixte. Aucun des modèles de
contenu que nous pouvons construire jusqu’à maintenant n’accepte de contenu mixte.
C’est justement pour pallier cette lacune que les modèles de contenu mixte existent.
Avant de voir la forme générale, voyons un exemple. En tenant pour acquis que
item
accepte du texte :
<!ELEMENT item (#PCDATA)>
voici comment on pourrait déclarer l’élément liste
pour qu’il accepte
le contenu de l’exemple :
<!ELEMENT liste (#PCDATA | item)*>
Le modèle de contenu mixte est ici (#PCDATA | item)*
. La façon la plus
simple d’interpréter ce modèle de contenu est de dire qu’il agit exactement comme
(item)*
, sauf qu’avant, après et/ou entre les éléments
item
, il peut y avoir non seulement des espaces blancs et des
commentaires, mais du texte arbitraire.
Notez qu’à cause de la présence du facultatif-et-répétable
« *
» dans le modèle de contenu, il n’est pas possible de contrôler
le nombre d’item
s dans le contenu, ni le nombre d’interstices entre les
éléments où il y a du texte non blanc. Ainsi, les exemples suivants seraient aussi
valides :
<liste>Voici deux
items:
<item>1</item>
<item>2</item>
et en voici
un autre:
<item>3</item>
</liste>
<liste>Aucun item dans cette "liste"
!?!</liste>
Toujours à cause du facultatif-et-répétable, un contenu vide ou ne consistant qu’en des espaces blancs (et d’éventuels commentaires) sera aussi accepté. Tous les exemples suivants seraient donc aussi valides :
<liste></liste>
<liste/>
<liste>
<!-- Un jour, inscrire ici une série
d’items… -->
</liste>
La forme générale d’un modèle de contenu mixte est :
(#PCDATA | élément1 | élément2 | … | élémentn)*
où élément1
, élément2
, …,
élémentn
sont tous des éléments déclarés ailleurs dans la
DTD. Ils peuvent alors tous survenir dans les contenus acceptés, dans n’importe quel
ordre et en n’importe quel nombre. Comme dans notre exemple, du texte arbitraire
peut se retrouver entre les éléments. Voici un modèle de contenu qui pourrait être
utilisé pour un contenu textuel où, comme en HTML, certains passages peuvent être
mis en emphase simple (em
) ou appuyée (strong
) :
(#PCDATA | em | strong)*
En supposant em
et strong
déclarés avec modèle de contenu
(#PCDATA)
, ceci serait un exemple de contenu accepté :
Texte avec des <em>bouts en emphase simple</em> et des <strong>bouts en emphase appuyée</strong>.
Les modèles de contenu mixte sont les seuls cas où (#PCDATA)
peut être combiné avec un opérateur ou avec des noms d’élément. Comme nous avons
souligné plus tôt, la règle de combinaison ne permet pas d’utiliser librement
(#PCDATA)
dans un modèle de contenu quelconque.
EMPTY
Il arrive que, dans un modèle XML, un élément doive être introduit simplement pour
marquer un endroit dans un document, et non pour contenir quelque chose. Un
parfait exemple est l’élément hr
(pour horizontal rule) en
HTML, dont la seule fonction est de causer l’affichage d’une ligne horizontale à un
certain endroit dans le document. L’élément lui-même n’a aucun contenu utile, seule
sa position à l’intérieur du document importe.
Pour ces cas, il est possible de déclarer qu’un élément doit toujours être
vide. C’est ce que fait le modèle de contenu EMPTY
.
Le hr
de HTML pourrait par exemple être déclaré comme suit :
<!ELEMENT hr EMPTY>
Comme nous avons dit, EMPTY
est un des seuls modèles de contenu
s’écrivant sans parenthèses.
Un élément déclaré EMPTY
ne peut contenir aucun espace blanc (espace,
saut de ligne, tabulation, etc.), ni même de commentaire. La façon la plus simple
pour un auteur d’écrire un tel élément est d’utiliser une balise auto-fermante. Si
des balises de début et de fin distinctes sont utilisées, il faut s’assurer qu’elles
se « touchent ». Ainsi, notre hr
doit s’écrire :
<hr/>
ou :
<hr></hr>
ATTLIST
En XML bien formé, dès qu’on a une balise de début ou auto-fermante, on peut y ajouter toutes les spécifications d’attribut que l’on veut, sans restriction (à condition de ne pas spécifier deux fois le même attribut dans la même balise). En XML valide, c’est la modélisatrice qui décide quels attributs peuvent être spécifiés sur chaque type d’élément de la DTD.
Cela suppose que la modélisatrice a déterminé quelles informations elle veut voir inscrites dans le contenu des éléments, et quelles informations elle désire voir inscrites en tant que valeurs de certains attributs sur certains éléments. On dit parfois que les informations consignées comme valeurs d’attribut sont des informations complémentaires que l’on n’afficherait pas nécessairement dans une version imprimée du document, mais c’est loin d’être une règle absolue. La modélisatrice a à ce chapitre une liberté totale. Quoi qu’il en soit, nous supposons ici que cette réflexion a été faite par la modélisatrice et nous concentrons seulement sur la façon dont elle doit représenter ses choix dans sa DTD.
C’est par le truchement de déclarations
ATTLIST
dans sa DTD que la modélisatrice définit les
restrictions qu’elle souhaite imposer à l’utilisation d’attributs.
Encore une fois, commençons par un exemple. Retournons aux notifications
d’absence. Notre modélisatrice a déjà prévu l’élément
titre-du-cours-manqué
, mais elle est bien consciente que les
professeurs pourraient ne pas toujours inscrire cette information exactement de la
même façon. Dans l’optique de faire une compilation automatisée des données, cela
poserait un problème. En effet, pour le cours « Histoire de l’art 301 », certains
pourraient écrire « Hist. art 301. », d’autres « Histoire de l'art-301 », d’autres
encore « Histoire de l’art - 301. », etc. Or, toutes ces variantes devraient être
considérées comme identifiant le même cours. La réconciliation de toutes ces formes
par un programme informatique serait pour le moins ardue.
Pour minimiser l’effet de cet éparpillement des formes, la modélisatrice décide de faire inscrire, en plus du titre, le sigle du cours, qui est moins sujet aux variations de forme. En effet, les sigles ont tous la même forme très simple et risquent moins d’être déformés que les titres. La compilation des données pourra être basée sur les sigles de cours, plutôt que sur les titres, et sera donc plus fiable.
Elle décide de faire du sigle du cours un attribut de l’élément
titre-du-cours-manqué
. Elle ajoutera donc à sa DTD la déclaration
suivante, qui rendra possible – en fait même, obligatoire – l’utilisation d’un
attribut sigle
sur l’élément titre-du-cours-manqué
:
<!ATTLIST titre-du-cours-manqué sigle NMTOKEN #REQUIRED>
L’effet de cette déclaration est de rendre l’attribut sigle
obligatoire sur tout élément titre-du-cours-manqué
. Autrement dit, dès
qu’un professeur inscrit un élément titre-du-cours-manqué
, il n’a pas
le choix : il doit inscrire un attribut sigle
dans la balise
de début, sinon son document est invalide.
Ainsi, ceci serait valide :
<titre-du-cours-manqué sigle="GEO101">Géographie 101</titre-du-cours-manqué>
mais pas ceci :
INVALIDE :
<titre-du-cours-manqué>Géographie 101</titre-du-cours-manqué>
Rappelez-vous que les contraintes exprimées via une DTD ne sont que des contraintes de forme. Un document valide respecte une forme imposée, mais il demeure de la responsabilité de son auteur d’inscrire les bonnes informations aux bons endroits. Si un professeur inscrit des informations incorrectes ou farfelues :
<titre-du-cours-manqué sigle='ZZZ999'>Blagues 100 limites</titre-du-cours-manqué>
l’élément est quand même valide. Une DTD (comme un formulaire) ne peut que donner au document une forme propice à la bonne saisie des informations, mais ne peut la garantir.
Dans la déclaration de notre attribut, on retrouve les mots-clés
NMTOKEN
et #REQUIRED
. Ce dernier indique que l’attribut
est obligatoire, c’est-à-dire qu’il doit être spécifié sur toute occurrence
de l’élément titre-du-cours-manqué
. Quant à NMTOKEN
, il
précise le type de valeur que l’attribut peut prendre (rappelez-vous que la
valeur d’un attribut est ce qui est donné entre guillemets simples ou doubles après
le signe = dans la spécification d’attribut). Essentiellement, le type
NMTOKEN
indique que la valeur doit être constituée d’un et un seul
mot (nous verrons les règles précises plus loin). Même si l’attribut est spécifié,
si sa valeur n’a pas cette forme, l’élément est invalide. Les exemples suivants
seraient donc invalides :
INVALIDE : <titre-du-cours-manqué
sigle="GEO 101">Géographie 101</titre-du-cours-manqué>
INVALIDE : <titre-du-cours-manqué
sigle="GEO,101">Géographie 101</titre-du-cours-manqué>
La forme générale d’une déclaration ATTLIST
couverte dans ce premier
tour d’horizon est :
<!ATTLIST type-d-élément nom-d-attribut type-de-valeur obligatoire-ou-non >
Le type-d-élément
identifie le type d’élément auquel
l’attribut déclaré s’appliquera. Le nom-d-attribut
est celui
par lequel l’attribut devra être spécifié dans les balises de début (ou
auto-fermantes) des éléments de type type-d-élément
. Le
type-de-valeur
, que l’on appelle aussi type
d’attribut, précise le type de valeur que l’attribut pourra prendre; nous y
reviendrons plus tard.
La partie suivante,
obligatoire-ou-non
,
indique si l’attribut est obligatoire ou
non :
#REQUIRED
.#IMPLIED
.Voyons maintenant les principaux types que l’on peut spécifier comme
type-de-valeur
pour l’attribut déclaré.
CDATA
Le type CDATA
(qui signifie Character Data)
indique qu’il n’y a en fait aucune restriction sur la valeur que l’attribut peut
prendre : n’importe quelle chaîne de caractères peut être spécifiée comme valeur –
du moment qu’elle ne contient pas de guillemet du même type (simple ou double) que
celui utilisé pour délimiter la valeur. (Les caractères « <
» et
« &
» peuvent se retrouver dans la valeur, mais ils doivent bien
sûr être représentés par les appels d’entité « <
» et
« &
».)
NMTOKEN
Le type NMTOKEN
(pour Name Token), utilisé dans
notre exemple ci-dessus, indique que la valeur de l’attribut doit respecter les règles d’un nom XML, sans toutefois avoir besoin
de commencer par une lettre ou un caractère de soulignement _ . En
particulier, la valeur peut commencer par un chiffre.
Types énumérés
Contrairement aux deux types précédents, les types
énumérés ne sont pas représentés par un mot-clé. Le principe d’un type
énuméré est qu’au lieu de spécifier la forme générale des valeurs acceptées, la
modélisatrice va énumérer une par une toutes les valeurs acceptées.
Évidemment, un type énuméré n’est applicable que si l’ensemble des valeurs possibles
est fini et s’il est connu à l’avance. Une autre restriction à
l’utilisation d’un type énuméré est que chacune des valeurs possibles doit avoir une
forme acceptée par le type NMTOKEN
.
Un type énuméré s’écrit comme suit : les différentes valeurs possibles sont inscrites sans guillemets, l’une après l’autre, séparées par une barre verticale « | », le tout entre parenthèses. Des exemples sont donnés ci-après.
Certains ensembles de valeurs se prêtent particulièrement bien à un type énuméré, par exemple les noms de mois, de jours de la semaine, ou des ensembles très restreints de valeurs numériques (par exemple, une valeur entière entre 1 et 10). Ces types énumérés s’exprimeraient respectivement comme suit :
(janvier | février | mars | avril | mai | juin | juillet |
août | septembre | octobre | novembre | décembre)
(lundi | mardi | mercredi | jeudi | vendredi | samedi |
dimanche)
(1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10)
Voici un exemple de déclaration ATTLIST
complète avec un type
énuméré :
<!ATTLIST appréciation cote (1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10) #REQUIRED>
Pour les attributs de types NMTOKEN
et énumérés, une valeur conforme
au type est dite valide, sinon elle est invalide. Si une valeur invalide est
spécifiée, on dira aussi que la spécification d’attribut (la partie
attrib="valeur"
dans la balise) est invalide, tout comme l’élément
porteur de l’attribut fautif et le document dans son entier. Ainsi, avec la
déclaration de l’attribut cote
ci-dessus, l’élément suivant est
invalide :
INVALIDE :
<appréciation cote="11">…</appréciation>
Notons que si la valeur spécifiée contient des espaces initiaux et/ou finaux, ceux-ci sont ignorés. Ainsi, toujours avec la même déclaration, cet élément est valide :
<appréciation cote=" 5 ">…</appréciation>
Si on spécifie un attribut non déclaré, l’élément porteur de l’attribut non déclaré
est invalide, tout comme le document dans son entier. Ainsi, si on tient pour acquis
que cote
est le seul attribut déclaré pour l’élément
appréciation
, l’élément suivant est invalide :
INVALIDE :
<appréciation cote="3" auteur="AF">…</appréciation>
Il est bien sûr possible de déclarer plusieurs attributs pour le même type
d’élément. À titre d’illustration, nous allons poursuivre l’exemple du type
titre-du-cours-manqué
, auquel nous avons déjà ajouté un attribut
sigle
. Supposons que certains cours sont subdivisés en plusieurs
groupes-cours, parfois jusqu’à quatre groupes. Il pourrait être intéressant de
compiler les absences non seulement par cours manqué, mais également par
groupe-cours. Par contre, certains cours ne sont pas subdivisés.
La modélisatrice décide donc d’ajouter un second attribut à
titre-du-cours-manqué
, facultatif, appelé groupe
, et qui
pourra prendre une valeur entière entre 1 et 4 :
<!ATTLIST titre-du-cours-manqué groupe (1 | 2 | 3 | 4) #IMPLIED>
La DTD contiendra donc deux déclarations ATTLIST
mentionnant le type
d’élément titre-du-cours-manqué
. Toute balise de début d’un élément
titre-du-cours-manqué
contiendra nécessairement une spécification
d’attribut pour sigle
, puisque cet attribut est obligatoire, et
peut-être une autre pour groupe
, puisque ce dernier est facultatif.
Voici un exemple valide selon ces déclarations :
<titre-du-cours-manqué sigle="GEO101" groupe="2">Géographie 101</titre-du-cours-manqué>
Rappelez-vous que l’ordre des spécifications d’attribut à l’intérieur d’une balise est sans importance. L’élément suivant serait donc strictement équivalent au précédent :
<titre-du-cours-manqué groupe="2" sigle="GEO101">Géographie 101</titre-du-cours-manqué>
Voici un autre exemple valide, cette fois sans l’attribut groupe
:
<titre-du-cours-manqué sigle="GEO101">Géographie 101</titre-du-cours-manqué>
Comme pour les déclarations ELEMENT
, l’ordre des déclarations
ATTLIST
n’a aucune importance. Elles peuvent aussi être entremêlées
avec les déclarations ELEMENT
de façon complètement arbitraire.
Cependant, une pratique courante est de placer les déclarations ATTLIST
se rapportant à un type d’élément juste après la déclaration ELEMENT
de
ce type d’élément.
Si on tient compte des ajouts effectués jusqu’ici, notre DTD pour les notifications d’absence comporte maintenant les neuf déclarations suivantes :
<!ELEMENT notification-d-absence (date-de-l-absence, nom-de-l-élève, titre-du-cours-manqué, motif?)>
<!ELEMENT date-de-l-absence (#PCDATA)>
<!ELEMENT nom-de-l-élève (prénom, nom-de-famille)>
<!ELEMENT titre-du-cours-manqué (#PCDATA)>
<!ATTLIST titre-du-cours-manqué sigle NMTOKEN #REQUIRED>
<!ATTLIST titre-du-cours-manqué groupe (1 | 2 | 3 | 4) #IMPLIED>
<!ELEMENT motif (#PCDATA)>
<!ELEMENT prénom (#PCDATA)>
<!ELEMENT nom-de-famille (#PCDATA)>
Pour référence, cette DTD est accessible ici. Vous pouvez utiliser le lien précédent pour créer un document valide selon cette DTD (par exemple dans oXygen, qui vous permettra de valider votre document).
Tel qu’évoqué précédemment, le scénario naturel de déploiement d’une DTD est de la
placer à un emplacement informatique accessible aux auteurs. Ce sera souvent sur le
Web, mais ce pourrait aussi être sur un intranet ou même sur un simple système de
fichiers. Les auteurs peuvent créer des documents valides en inscrivant l’adresse de
la DTD dans la déclaration DOCTYPE
de leurs documents. La DTD existe à
un seul endroit et les différents documents lui font simplement référence. Il n’y a
aucune réplication des déclarations. C’est le scénario habituel de déploiement d’une
DTD.
Cependant, si on est en apprentissage et que l’on veut créer des documents valides
simplement pour explorer le langage des DTD, travailler avec deux fichiers distincts
– un pour la DTD et un pour le document XML – est une nuisance qu’il est possible
d’éviter. En effet, il existe une forme particulière de la déclaration
DOCTYPE
qui permet d’intégrer les déclarations dans le document XML
lui-même. Ce n’est pas la façon normale de travailler, puisque les déclarations
incluses dans un document ne peuvent servir qu’à cet unique document, mais c’est un
truc utile en apprentissage ou pendant le développement d’une DTD, alors que les
changements dans les déclarations sont fréquents.
Cette forme particulière de déclaration DOCTYPE
est la suivante :
<!DOCTYPE ephn [
déclarations-de-la-DTD
]>
où ephn
doit, comme avant, être remplacé par le nom de
l’élément de plus haut niveau du document et
déclarations-de-la-DTD
doit être remplacé par la totalité
des déclarations de la DTD (généralement, sur plusieurs lignes). Le mot-clé
SYSTEM
suivi de l’URL de la DTD a été troqué pour une section entre
crochets [ ]
contenant les déclarations. Cette section entre crochets
est appelée le sous-ensemble local de déclarations du document.
Voici un exemple de document valide selon notre DTD, avec la DTD incluse dans le document lui-même (pour faciliter la lecture, nous montrons la DTD en vert) :
<!DOCTYPE notification-d-absence [
<!ELEMENT notification-d-absence (date-de-l-absence, nom-de-l-élève, titre-du-cours-manqué, motif?)>
<!ELEMENT date-de-l-absence (#PCDATA)>
<!ELEMENT nom-de-l-élève (prénom, nom-de-famille)>
<!ELEMENT titre-du-cours-manqué (#PCDATA)>
<!ATTLIST titre-du-cours-manqué sigle NMTOKEN #REQUIRED>
<!ATTLIST titre-du-cours-manqué groupe (1 | 2 | 3 | 4) #IMPLIED>
<!ELEMENT motif (#PCDATA)>
<!ELEMENT prénom (#PCDATA)>
<!ELEMENT nom-de-famille (#PCDATA)>
]>
<notification-d-absence>
<date-de-l-absence>2036-01-31</date-de-l-absence>
<nom-de-l-élève>
<prénom>Clotaire</prénom>
<nom-de-famille>Euler</nom-de-famille>
</nom-de-l-élève>
<titre-du-cours-manqué sigle='MAT101'>Mathématiques 101</titre-du-cours-manqué>
</notification-d-absence>
Quand on utilise cette forme de déclaration DOCTYPE
, on place
habituellement les déclarations de la DTD légèrement en retrait (comme nous avons
fait) pour faciliter la lecture, mais ce n’est pas obligatoire.
Une DTD ainsi incluse dans un document est dite interne. Quand la DTD est un fichier séparé des documents (le scénario « normal »), on dit que la DTD est externe.
Pour référence, ce document est disponible ici. Faites afficher la source si vous voulez voir le XML brut.
Plusieurs des exemples et exercices du cours utilisent cette forme compacte de document valide.