Lisez-moi S.V.P. 

D. Construction des modules DTD

Sommaire

Cette section est normative.

Les modules XHTML sont mis en œuvre comme des fragments DTD. Lorsque ces fragments sont assemblés de manière spécifique (décrite à la section Développement de définitions DTD avec des modules définis et étendus), la définition DTD obtenue est une représentation d'un type de document complet. Cette représentation peut alors être utilisée pour la validation des instances du type de document.

Les clés de la combinaison de ces fragments en une définition DTD significative sont les règles utilisées pour définir les fragments. Cette section définit ces règles. En observant ces règles, les créateurs de définitions DTD peuvent être assurés que leurs modules s'interfaceront proprement avec d'autres modules compatibles avec XHTML.

Les modules conformes à ces règles doivent également satisfaire aux exigences de conformité définies à la section Conformité du module à la famille XHTML pour prétendre au titre de modules de la famille XHTML.

D.1. Nommage des entités paramètres

Cette spécification classe les entités paramètres en sept catégories et les nomme systématiquement en utilisant les suffixes suivants :

.mod
Les entités paramètres emploient le suffixe .mod lorsqu'elles servent à représenter un module DTD (une collection d'éléments, d'attributs, d'entités paramètres, etc.). Dans cette spécification, chaque module est une unité atomique et peut être représenté comme une entité de fichier séparée.
.module
Les entités paramètres emploient le suffixe .module lorsqu'elles servent à contrôler l'inclusion d'un module DTD en contenant l'un des deux mots-clés de section conditionnelle INCLUDE ou IGNORE.
.qname
Les entités paramètres emploient le suffixe .qname lorsqu'elles servent à représenter le nom qualifié d'un élément. Cf. la section Définition de l'espace de noms d'un module pour davantage d'informations sur les noms qualifiés.
.content
Les entités paramètres emploient le suffixe .content lorsqu'elles servent à représenter le modèle de contenu d'un type d'élément.
.class
Les entités paramètres emploient le suffixe .class lorsqu'elles servent à représenter des éléments de la même classe.
.mix
Les entités paramètres emploient le suffixe .mix lorsqu'elles servent à représenter une collection de types d'élément provenant de classes différentes.
.attrib
Les entités paramètres emploient le suffixe .attrib lorsqu'elles servent à représenter un groupe d'atomes représentant une ou plusieurs spécifications d'attribut complètes au sein d'une déclaration ATTLIST.

Par exemple, dans HTML 4, l'entité paramètre %block; est définie pour représenter la collection hétérogène des types d'éléments qui sont des éléments de type block. Dans cette spécification, l'entité paramètre corollaire est %Block.mix;.

Lors de la définition d'entités paramètres dans les classes définies ici, les modules devraient définir la portée (scope) la portée des noms des entités en utilisant des préfixes uniques. Par exemple, le modèle de contenu de l'élément myelement dans le module mymodule pourrait se nommer MYMODULE.myelement.content. D'autres systèmes sont possibles. Quel que soit le système utilisé, les créateurs de modules devraient s'efforcer d'attribuer un nom unique aux entités paramètres qu'ils définissent afin que ces entités paramètres n'entrent pas en conflit avec d'autres et que les méthodes d'interface du module soient claires pour leurs utilisateurs.

D.2. Définition de l'espace de noms d'un module

XHTML impose que les éléments et attributs déclarés dans un module soient dans un espace de noms XML défini [XMLNAMES]. L'identification de cet espace de noms est une adresse URI arbitraire. XHTML impose, lorsque le module est mis en œuvre à l'aide d'une définition DTD XML, que ce module déclare l'espace de noms d'une manière spéciale. La raison de cela est de permettre, au moment de l'analyse ou de la validation du document, la sélection de l'utilisation des préfixes d'espace de noms et du préfixe utilisé pour identifier les éléments et attributs du module.

Les développeurs de contenus qui souhaitent créer des documents fondés sur des types de document hybrides peuvent choisir d'employer des préfixes d'espace de noms XML sur les éléments de l'espace de noms XHTML, sur les éléments d'autres espaces de noms, ou sur les deux. Pour assurer que de tels documents soient conformes et rétrocompatibles avec les outils qui ne gèrent pas les espaces de noms, le W3C recommande aux développeurs de contenus de ne pas utiliser de préfixes d'espace de noms XML sur les éléments de l'espace de noms XHTML. Lorsque l'intérêt des développeurs de contenus est d'avoir leurs contenus traités par des processeurs compatibles avec les espaces de noms, le W3C recommande en outre de spécifier les éléments des espaces de noms non-XHTML à l'aide d'un préfixe d'espace de nom XML plutôt que de compter sur les mécanismes par défaut des espaces de noms XML (XML namespace defaulting mechanisms).

Chaque module conforme à XHTML mis en œuvre en tant que définition DTD XML doit obligatoirement définir un préfixe d'espace de noms XML par défaut, une méthode pour changer ce préfixe dans une instance de document et une section marquée qui active le traitement du préfixe.

Notez qu'il est légal et prévu que plusieurs modules fassent partie du même espace de noms lorsque ceux-ci sont liés. Ainsi tous les modules XHTML appartiennent au même espace de noms.

D.2.1. Sous-module des noms qualifiés

Il faut d'abord définir un sous-module des noms qualifiés (un sous-module est simplement une entité de fichier à part afin qu'on puisse l'incorporer dans la définition DTD finale à l'endroit approprié). Le sous-module des noms qualifiés se construit en observant les étapes suivantes (où on remplace la chaîne "MODULE" par la chaîne appropriée du nouveau module) :

  1. Définir une entité paramètre MODULE.prefixed qui annonce si les éléments du module sont utilisés ou non avec des noms préfixés d'un espace de noms XML. La valeur par défaut de cette entité paramètre devrait être "%NS.prefixed;". L'entité paramètre NS.prefixed est définie par le cadre XHTML comme étant IGNORE par défaut, et peut être utilisée dans une instance de document pour activer le préfixage (prefixing) de tous les espaces de noms inclus (y compris celui des modules XHTML) ;
  2. Définir une entité paramètre MODULE.xmlns qui contient l'identificateur d'espace de noms de ce module ;
  3. Définir une entité paramètre MODULE.prefix qui contient la chaîne de préfixe par défaut à utiliser lorsque le préfixage est activé ;
  4. Définir une entité paramètre MODULE.pfx qui est "%MODULE.prefix;:" si le préfixage est activé et "" sinon ;
  5. Définir une entité paramètre MODULE.xmlns.extra.attrib qui contient la déclaration des attributs d'espace de noms XML des espaces de noms référencés par ce module (par exemple, xmlns:xlink). Si %MODULE.prefixed a la valeur INCLUDE, cet attribut devrait également inclure la déclaration xmlns:%MODULE.prefix; ;
  6. Définir une entité paramètre XHTML.xmlns.extra.attrib comme étant MODULE.xmlns.extra.attrib. Cette définition est normalement écrasée par le fichier pilote du type de document, mais si ce n'est pas le cas elle prendra effet comme valeur par défaut ;
  7. Pour chaque élément défini par le module, créer une entité paramètre de la forme "MODULE.NAME.qname" qui portera son nom qualifié. La valeur de cette entité paramètre doit être "%MODULE.pfx;NAME". Ainsi la valeur interprétée sera "PREFIX:NAME" si les préfixes sont activés et "NAME" sinon.

    Si le module ajoute des attributs aux éléments définis dans des modules qui ne partagent pas son espace de noms, déclarer ces attributs pour qu'ils utilisent le préfixe %MODULE.pfx. Par exemple :

    <ENTITY % MODULE.img.myattr.qname "%MODULE.pfx;myattr" >
    

Voici l'exemple du sous-module de noms qualifiés d'un hypothétique module Inventory :

Cette version du fichier est récupérable à http://www.w3.org/TR/2008/REC-xhtml-modularization/DTD/examples/inventory-qname-1.mod. La dernière version est disponible à http://www.w3.org/MarkUp/DTD/examples/inventory-qname-1.mod.

<!-- ...................................................................... -->
<!-- Inventory Qname Module ................................................... -->
<!-- file: inventory-qname-1.mod

     PUBLIC "-//MY COMPANY//ELEMENTS XHTML Inventory Qnames 1.0//EN"
     SYSTEM "http://www.example.com/DTDs/inventory-qname-1.mod"

     xmlns:inventory="http://www.example.com/xmlns/inventory"
     ...................................................................... -->

<!-- Declare the default value for prefixing of this module's elements -->
<!-- Note that the NS.prefixed will get overridden by the XHTML Framework or
     by a document instance. -->
<!ENTITY % NS.prefixed "IGNORE" >
<!ENTITY % Inventory.prefixed "%NS.prefixed;" >

<!-- Declare the actual namespace of this module -->
<!ENTITY % Inventory.xmlns "http://www.example.com/xmlns/inventory" >

<!-- Declare the default prefix for this module -->
<!ENTITY % Inventory.prefix "inventory" >

<!-- Declare the prefix for this module -->
<![%Inventory.prefixed;[
<!ENTITY % Inventory.pfx "%Inventory.prefix;:" >
]]>
<!ENTITY % Inventory.pfx "" >

<!-- Declare the xml namespace attribute for this module -->
<![%Inventory.prefixed;[
<!ENTITY % Inventory.xmlns.extra.attrib
    "xmlns:%Inventory.prefix;   %URI.datatype;  #FIXED  '%Inventory.xmlns;'" >
]]>
<!ENTITY % Inventory.xmlns.extra.attrib "" >

<!-- Declare the extra namespace that should be included in the XHTML
     elements -->
<!ENTITY % XHTML.xmlns.extra.attrib
    "%Inventory.xmlns.extra.attrib;" >

<!-- Now declare the qualified names for all of the elements in the
     module -->
<!ENTITY % Inventory.shelf.qname "%Inventory.pfx;shelf" >
<!ENTITY % Inventory.item.qname "%Inventory.pfx;item" >
<!ENTITY % Inventory.desc.qname "%Inventory.pfx;desc" >
<!ENTITY % Inventory.sku.qname "%Inventory.pfx;sku" >
<!ENTITY % Inventory.price.qname "%Inventory.pfx;price" >

D.2.2. Sous-module(s) de déclaration

Il faut ensuite définir un ou plusieurs sous-modules de déclaration (declaration sub-modules). La raison-d'être de ces entités fichiers est de déclarer les éléments et les listes d'attributs de la définition DTD XML. La construction d'un module de déclaration XHTML devrait se dérouler comme suit :

  1. Définir une entité paramètre à utiliser dans la liste ATTLIST de chaque élément déclaré. Cette entité paramètre devrait contenir %NS.decl.attrib; lorsque l'entité %MODULE.prefixed; vaut INCLUDE, et %NS.decl.attrib; plus "xmlns %URI.datatype; #FIXED '%MODULE.xmlns;'" lorsque %MODULE.prefixed; vaut IGNORE ;
  2. Déclarer tous les éléments et attributs du module. Dans chaque liste ATTLIST d'un élément, inclure l'entité paramètre définie ci-dessus afin que tous les attributs xmlns obligatoire soient utilisables sur chaque élément dans le module ;
  3. Si le module ajoute des attributs aux éléments définis dans des modules qui ne partagent pas son espace de noms, déclarer ces attributs pour utiliser le préfixe %MODULE.pfx. Par exemple :

    <ENTITY % MODULE.img.myattr.qname "%MODULE.pfx;myattr" >
    <!ATTLIST %img.qname;
          %MODULE.img.myattr.qname;    CDATA          #IMPLIED
    >
    

    Cela ajoutera un attribut à l'élément img du module Image, mais l'attribut aura un nom qualifié, incluant le préfixe, lorsque les préfixes sont sélectionnés pour une instance du document. Cela ajoute aussi l'attribut xmlns:MODULE_PREFIX à la liste d'attributs de l'élément img afin qu'un analyseur compatible avec les espaces de noms XML sache comment résoudre l'espace de noms d'après son préfixe.

L'exemple suivant montre un sous-module de déclaration du module hypothétique Inventory :

Cette version du fichier est récupérable à http://www.w3.org/TR/2008/REC-xhtml-modularization/DTD/examples/inventory-1.mod. La dernière version est disponible à http://www.w3.org/MarkUp/DTD/examples/inventory-1.mod.

<!-- ...................................................................... -->
<!-- Inventory Elements Module ................................................... -->
<!-- file: inventory-1.mod

     PUBLIC "-//MY COMPANY//ELEMENTS XHTML Inventory Elements 1.0//EN"
     SYSTEM "http://www.example.com/DTDs/inventory-1.mod"

     xmlns:inventory="http://www.example.com/xmlns/inventory"
     ...................................................................... -->

<!-- Inventory Module

     shelf
        item
       sku
       desc
       price

     This module defines a simple inventory item structure
-->

<!-- Define the global namespace attributes -->
<![%Inventory.prefixed;[
<!ENTITY % Inventory.xmlns.attrib
    "%NS.decl.attrib;"
>
]]>
<!ENTITY % Inventory.xmlns.attrib
     "%NS.decl.attrib;
     xmlns  %URI.datatype;  #FIXED '%Inventory.xmlns;'"
>

<!-- Define a common set of attributes for all module elements -->
<!ENTITY % Inventory.Common.attrib
         "%Inventory.xmlns.attrib;
      id               ID                   #IMPLIED"
>

<!-- Define the elements and attributes of the module -->
<!ELEMENT %Inventory.shelf.qname;
     ( %Inventory.item.qname; )* >
<!ATTLIST %Inventory.shelf.qname;
     location   CDATA   #IMPLIED
     %Inventory.Common.attrib;
>
<!ELEMENT %Inventory.item.qname;
     ( %Inventory.desc.qname;, %Inventory.sku.qname;, %Inventory.price.qname;) >
<!ATTLIST %Inventory.item.qname;
     location   CDATA   #IMPLIED
     %Inventory.Common.attrib;
>

<!ELEMENT %Inventory.desc.qname; ( #PCDATA ) >
<!ATTLIST %Inventory.desc.qname;
     %Inventory.Common.attrib;
>

<!ELEMENT %Inventory.sku.qname; ( #PCDATA ) >
<!ATTLIST %Inventory.sku.qname;
     %Inventory.Common.attrib;
>

<!ELEMENT %Inventory.price.qname; ( #PCDATA ) >
<!ATTLIST %Inventory.price.qname;
     %Inventory.Common.attrib;
>

<!-- end of inventory-1.mod -->

D.2.3. Utilisation du module comme définition DTD autonome

Il est parfois souhaitable d'avoir un module XHTML qui soit aussi utilisable comme une définition DTD autonome. Un bon exemple serait notre module Inventory ci-dessus. Ces éléments (items) doivent pouvoir être incorporés dans un document XHTML et aussi être disponibles comme des documents autonomes, par exemple, extraits d'une base de données. La méthode la plus facile d'y parvenir est de définir un fichier DTD qui instancie les composants du module. Une telle définition DTD aurait la structure suivante :

  1. Inclure le module des types de données XHTML (le module des noms qualifiés utilise probablement certains d'eux — il utilise certainement le type de données URI pour l'attribut xmlns) ;
  2. Inclure le module des noms qualifiés du module ;
  3. Définir l'entité paramètre NS.decl.attrib comme étant %MODULE.xmlns.extra.attrib; ;
  4. Inclure le(s) module(s) de déclaration du module.

En voici un exemple pour notre module Inventory :

Cette version du fichier est récupérable à http://www.w3.org/TR/2008/REC-xhtml-modularization/DTD/examples/inventory-1.dtd. La dernière version est disponible à http://www.w3.org/MarkUp/DTD/examples/inventory-1.dtd.

<!-- ...................................................................... -->
<!-- Inventory Elements DTD ............................................... -->
<!-- file: inventory-1.dtd

     PUBLIC "-//MY COMPANY//DTD XHTML Inventory 1.0//EN"
     SYSTEM "http://www.example.com/DTDs/inventory-1.dtd"

     xmlns:inventory="http://www.example.com/xmlns/inventory"
     ...................................................................... -->

<!-- Inventory Module

     shelf
        item
       sku
       desc
       price

     This module defines a simple inventory item structure
-->

<!-- Bring in the datatypes -->
<!ENTITY % xhtml-datatypes.mod
         PUBLIC "-//W3C//ENTITIES XHTML Datatypes 1.0//EN"
         "http://www.w3.org/MarkUp/DTD/xhtml-datatypes-1.mod" >
%xhtml-datatypes.mod;

<!-- Bring in the qualified names -->
<!ENTITY % Inventory-qname.mod SYSTEM "inventory-qname-1.mod" >
%Inventory-qname.mod;

<!ENTITY % NS.decl.attrib "%Inventory.xmlns.extra.attrib;">

<!ENTITY % Inventory.mod SYSTEM "inventory-1.mod" >
%Inventory.mod;

<!-- end of inventory-1.dtd -->

Cette définition DTD peut alors être référencée par les documents qui utilisent seulement les éléments du module :

Cette version du fichier est récupérable à http://www.w3.org/TR/2008/REC-xhtml-modularization/DTD/examples/inventory.xml. La dernière version est disponible à http://www.w3.org/MarkUp/DTD/examples/inventory.xml.

<!DOCTYPE shelf SYSTEM "inventory-1.dtd">
<shelf xmlns="http://www.example.com/xmlns/inventory">
    <item>
        <desc>
      this is a description.
    </desc>
        <sku>
      this is the price.
        </sku>
        <price>
      this is the price.
    </price>
    </item>
</shelf>

Cette méthode permet la définition d'éléments et d'attributs qui sont visibles (scoped) dans leur propre espace de noms. Elle permet aussi aux développeurs de contenus d'utiliser le préfixe par défaut des éléments et attributs :

Cette version du fichier est récupérable à http://www.w3.org/TR/2008/REC-xhtml-modularization/DTD/examples/inventory-prefixed.xml. La dernière version est disponible à http://www.w3.org/MarkUp/DTD/examples/inventory-prefixed.xml.

<!DOCTYPE inventory:shelf SYSTEM "inventory-1.dtd" [
    <!ENTITY % Inventory.prefixed "INCLUDE">
]>
<inventory:shelf xmlns:inventory="http://www.example.com/xmlns/inventory">
    <inventory:item>
        <inventory:desc>
          this is a description.
        </inventory:desc>
        <inventory:sku>
          this is the sku.
        </inventory:sku>
        <inventory:price>
          this is the price.
        </inventory:price>
    </inventory:item>
</inventory:shelf>

Enfin, une instance du document peut employer un préfixe d'espace de noms XML différent en le redéclarant dans l'en-tête DOCTYPE et son sous-ensemble interne (internal subset) :

Cette version du fichier est récupérable à http://www.w3.org/TR/2008/REC-xhtml-modularization/DTD/examples/inventory-newprefix.xml. La dernière version est disponible à http://www.w3.org/MarkUp/DTD/examples/inventory-newprefix.xml.

<!DOCTYPE i:shelf SYSTEM "inventory-1.dtd" [
    <!ENTITY % Inventory.prefixed "INCLUDE">
    <!ENTITY % Inventory.prefix "i">
]>
<i:shelf xmlns:i="http://www.example.com/xmlns/inventory">
    <i:item>
        <i:desc>
          this is a description.
        </i:desc>
        <i:sku>
          this is the price.
        </i:sku>
        <i:price>
          this is the price.
        </i:price>
    </i:item>
</i:shelf>

D.2.4. Particularités des espaces de noms

Bien que l'approche décrite ici permette la définition de langages de balisages compatibles avec XML et les espaces de noms XML, certains comportements définis par la spécification des espaces de noms XML ne sont pas gérés :

  1. Les espaces de noms XML permettent la redéclaration de l'attribut xmlns pour un espace de noms en tout point dans l'arbre. Cela permet en outre à cette redéclaration de basculer entre espace de noms par défaut et utilisation avec préfixe, et permet le changement du préfixe. La méthode définie dans ce document ne le permet pas. Partout dans une instance de document, un espace de noms donné doit continuer d'utiliser le même préfixe d'espace de noms (lorsque le préfixage est utilisé), ou continuer d'être utilisé dans la visibilité par défaut (default scope) ;

  2. Lors d'une utilisation de l'espace de noms par défaut, il est légal de compter sur la définition DTD du document pour communiquer aux analyseurs l'espace de noms des éléments. Toutefois, puisque les processeurs compatibles avec les espaces de noms ne sont pas obligés d'inclure la définition DTD lors de l'évaluation d'un document, les développeurs de contenus devraient déclarer l'espace de noms XML à chaque fois que l'espace de noms change :

    ...
    <p>
       <myelement xmlns="..." />
    </p>