Accueil
 chercher             Plan du site             Info (English version) 
L'histoire de XML s'écrit en ce moment même. XMLfr vous aide à la suivre et à en dégager les tendances.Les listes de discussions XMLfr sont à votre disposition pour réagir sur nos articles ou simplement poser une question.Si vous ètes passionnée(e) par XML, pourquoi ne pas en faire votre métier ?XMLfr n'est heureusement pas le seul site où l'on parle de XML. Découvrez les autres grâce à XMLfr et à l'ODP.Les partenaires grâce auxquels XMLfr peut se développer.Pour tout savoir sur XMLfr.XMLfr sans fil, c'est possible !Pour ceux qui veulent vraiment en savoir plus sur XML.L'index du site.
 Si vous vous posez une question, vous n'êtes peut-être pas le premier...Les traductions en français des bibles XML.Ces articles sont des références dans leur domaine.Tout ce qu'il faut savoir pour démarrer sur un sujet XML...


Utilisation des langages de schéma pour exprimer des contraintes sur des répétitions d'éléments

Cet exemple simple mais problématique illustre bien le rôle respectif des différents langages de schémas.

Eric van der Vlist, Dyomedea (vdv@dyomedea.com).
jeudi 16 juin 2005

Table des matières

Question

Réponse

Avec W3C XML Schema

Avec RELAX NG

Avec Schematron

Références

Question

J'aimerais formuler une contrainte de ce genre:

<?xml version="1.0" encoding="UTF-8"?>
<record xmlns:dc="http://purl.org/dc/elements/1.1/">
    <dc:title xml:lang="fr"/><!-- obligatoire -->
    <dc:title xml:lang="en"/><!-- obligatoire -->
    <dc:title xml:lang="autre"/><!-- répétable, optionnel -->
</record>

Cela revient juste à dire : "avant de publier sur notre site, vous devez donner un titre français, un titre anglais, et d'autres langues si vous voulez".J'ai tourné W3C XML Schema dans tous les sens, et je n'y suis pas arrivé, avec ou sans espace de noms, en type global ou local... Est-ce que je me trompe ?

Réponse

Avec W3C XML Schema

Vous ne vous trompez pas, ce n'est pas possible avec W3C XML Schema et si vous essayez de définir des types différents pour vos trois types d'élément dc:title (français, anglais ou autre), vous aurez une erreur similaire à celle-ci (rapportée par Xerces-J) :

Description: E cos-element-consistent: Error for type'#AnonType_r
ecord'. Multiple elements with name 'title', with differenttypes,
 appear in the model group.URL: http://www.w3.org/TR/xmlschema-1/
#cos-element-consistent

C'est une restriction qui à première vue peut sembler similaire à celle qui interdit, dans une DTD, de définir des contenus différents pour un même élément. Elle suit cependant des motivations différentes.

Dans le cas des DTDs, on considère que le nom d'un élément détermine son type (pour la recommandation XML 1.0, le type d'un élément est d'ailleurs ce que nous appelons maintenant son nom).

C'est une pratique que je considère comme une bonne pratique dans le cas général : les vocabulaires qui définissent des contenus différents pour un même élément suivant son contexte sont difficiles à documenter et à comprendre. Le meilleur exemple en est W3C XML Schema lui-même qui abuse de cette possibilité et réutilise les mêmes noms d'élément avec des significations et des contenus totalement différents.

W3C XML Schema permet cependant cette pratique dans la grande majorité des cas et vous pourriez définir des éléments dc:title avec des contenus différents s'ils étaient dans des éléments différents de votre document, par exemple :

<?xml version="1.0" encoding="UTF-8"?>
<record xmlns:dc="http://purl.org/dc/elements/1.1/">
    <français><dc:title xml:lang="fr"/></français>
    <anglais><dc:title xml:lang="en"/></anglais>
    <autres><dc:title xml:lang="autre"/></autres>
</record>

Ce qui cause problème dans votre cas précis, c'est que les éléments dc:title se suivent et qu'un processeur de schéma ne peut pas savoir avant d'avoir examiné l'élément s'il se trouve en face de la première occurrence, de la seconde ou d'une suivante.

Accepter ce type de contrainte revient à accepter des schémas que nous qualifions de "non déterministes". J'ai consacré un chapitre entier à ce point dans mon livre sur RELAX NG disponible en ligne (en anglais).

Le schéma le plus proche de votre document est donc un schéma où vous définirez dans trois documents différents (un par espace de noms), l'attribut xml:lang :

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFor
mDefault="qualified"
  targetNamespace="http://www.w3.org/XML/1998/namespace" xmlns:dc
="http://purl.org/dc/elements/1.1/">
  <xs:attribute name="lang" type="xs:language"/>
</xs:schema> 

L'élément dc:title :

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFor
mDefault="qualified"
  targetNamespace="http://purl.org/dc/elements/1.1/" xmlns:dc="ht
tp://purl.org/dc/elements/1.1/">
  <xs:import namespace="http://www.w3.org/XML/1998/namespace" sch
emaLocation="xml.xsd"/>
  <xs:element name="title">
    <xs:complexType>
      <xs:attribute ref="xml:lang"/>
    </xs:complexType>
  </xs:element>
</xs:schema>

Et l'élément record :

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFor
mDefault="qualified"
  xmlns:dc="http://purl.org/dc/elements/1.1/">
  <xs:import namespace="http://purl.org/dc/elements/1.1/" schemaL
ocation="dc.xsd"/>
  <xs:element name="record">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="dc:title" minOccurs="2" maxOccurs="unbou
nded"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Avec ce schéma, vous contrôlerez que vous avez bien au moins deux titres mais vous ne pouvez pas contrôler que le premier est français et le second anglais.

Il y a autre chose qui n'était pas demandé dans votre énoncé mais que vous pouvez tester avec W3C XML Schema, c'est que vous n'avez pas deux titres pour le même langage. Pour cela, il suffit d'ajouter une clause xs:unique à la fin de la définition de votre élément record :

  <xs:element name="record">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="dc:title" minOccurs="2" maxOccurs="unbou
nded"/>
      </xs:sequence>
    </xs:complexType>
    <xs:unique name="langages">
      <xs:selector xpath="dc:title"/>
      <xs:field xpath="@xml:lang"/>
    </xs:unique>
  </xs:element>

Avec RELAX NG

RELAX NG accepte les schémas "non déterministes" (et même les schémas dits ambigus, voir à nouveau l'explication que j'en donne dans mon livre sur le sujet).

Avec la syntaxe compacte de RELAX NG, on écrira simplement :

default namespace = ""
namespace dc = "http://purl.org/dc/elements/1.1/"

start =
    element record {
        element dc:title {
            attribute xml:lang { "fr" }
        },
        element dc:title {
            attribute xml:lang { "en" }
        },
        element dc:title {
            attribute xml:lang { xsd:language - ("fr" | "en") }
        } *
    }

On notera que toutes les définitions (pour les trois espaces de noms utilisés) peuvent être mises dans un document unique.

Le schéma équivalent en syntaxe XML est :

<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns:dc="http://purl.org/dc/elements/1.1/" ns=""
  xmlns="http://relaxng.org/ns/structure/1.0"
  datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
  <start>
    <element name="record">
      <element name="dc:title">
        <attribute name="xml:lang">
          <value>fr</value>
        </attribute>
      </element>
      <element name="dc:title">
        <attribute name="xml:lang">
          <value>en</value>
        </attribute>
      </element>
      <zeroOrMore>
        <element name="dc:title">
          <attribute name="xml:lang">
            <data type="language">
              <except>
                <value>fr</value>
                <value>en</value>
              </except>
            </data>
          </attribute>
        </element>
      </zeroOrMore>
    </element>
  </start>
</grammar> 

Ces deux formes sont strictement équivalentes et elles spécifient que l'on doit avoir un premier titre en français, un deuxième en anglais et, de manière optionnelle, d'autres titres qui ne sont ni français ni anglais.

On répond donc parfaitement à l'énoncé mais on ne peut pas tester, avec RELAX NG, que deux titres ne sont pas définis pour la même langue puisque RELAX NG ne gère pas de contraintes d'intégrité de type xs:unique.

Avec Schematron

W3C XML Schema et RELAX NG sont des langages de schémas basés sur des grammaires et on peut se demander s'il est bien de leur ressort de vérifier des règles comme celles que nous avons cherché à vérifier et que l'on pourrait qualifier de "règles métier".

Schematron est le langage des règles métier par excellence. Tout comme RELAX NG, Schematron est désormais un standard ISO/DSDL.

Pour tester que le premier titre est français et le deuxième est anglais, il suffit d'écrire la règle suivante :

        <rule context="record">
            <assert test="dc:title[1]/@xml:lang = 'fr'">Le premie
r élément dc:title doit être en
                français</assert>
            <assert test="dc:title[2]/@xml:lang = 'en'">Le deuxiè
me élément dc:title doit être
                en anglais</assert>
        </rule>

Cette règle est exécutée dans le contexte de l'élément "record" et vérifie que les conditions exprimées sous forme d'expressions XPath dans les éléments "assert" sont vérifiées. Si elles ne le sont pas, le message d'erreur correspondant est affiché.

De même, pour tester que les titres sont uniques pour chaque langage, on écrira :

       <rule context="dc:title">
            <report test="@xml:lang = preceding-sibling::dc:title
/@xml:lang">Les titres
                (dc:title) doivent être uniques pour chaque langa
ge.</report>
        </rule>

Cette deuxième règle est exécutée dans le contexte de l'élément "dc:title" et elle affiche une erreur si la condition définie dans l'élément "report" est vérifiée (c'est à dire s'il existe un titre précédant le titre courant qui a le même attribut xml:lang).

Ces deux règles sont placées dans un schéma Schematron :

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.ascc.net/xml/schematron">
    <ns uri="http://purl.org/dc/elements/1.1/" prefix="dc"/>
    <pattern name="languages">
        <rule context="record">
            <assert test="dc:title[1]/@xml:lang = 'fr'">Le premie
r élément dc:title doit être en
                français</assert>
            <assert test="dc:title[2]/@xml:lang = 'en'">Le deuxiè
me élément dc:title doit être
                en anglais</assert>
        </rule>
        <rule context="dc:title">
            <report test="@xml:lang = preceding-sibling::dc:title
/@xml:lang">Les titres
                (dc:title) doivent être uniques pour chaque langa
ge.</report>
        </rule>
    </pattern>
</schema>

Un tel schéma est généralement utilisé en complément d'un schéma basé sur une grammaire (RELAX NG, W3C XML Schema ou même DTD) pour vérifier les règles qui ne sont pas du ressort de ces langages de schéma.

Dans notre cas, cela permet de conserver une certaine simplicité à la grammaire qui ne définit plus qu'un contenu unique et global pour l'élément dc:title et d'exprimer les règles métiers dans un langage dont c'est la vocation.

Références

  • Recommandation XML 1.0 : [vf] [vo]
  • Recommandation W3C XML Schéma1.0 (tome 0) : [vf] [vo]
  • Tutoriel RELAX NG (syntaxe XML) : [vo]
  • Tutoriel RELAX NG (syntaxe compacte) : [vo]
  • Schematron [vo]
  • Question initiale sur xml-tech@xmlfr.org.

Copyright 2005, Eric van der Vlist


 

Mots clés.



L'histoire de XML s'écrit en ce moment même. XMLfr vous aide à la suivre et à en dégager les tendances.


Les documents publiés sur ce site le sont sous licence "Open Content"
Conception graphique
  l.henriot  

Conception, réalisation et hébergement
Questions ou commentaires
  redacteurs@xmlfr.org