Link Search Menu Expand Document

Schéma XML - aller plus loin

Le prochain chapitre est l’occasion de terminer notre apprentissage des Schémas XML. Ce chapitre regroupe de nombreuses notions qui vous seront utiles pour décrire tous les documents XML possibles et imaginables.

Ce chapitre s’annonce très dense, accrochez-vous, le résultat en vaut la peine ! Au programme : la gestion du nombre d’occurrences d’un élément, la réutilisation des éléments, l’héritage, les identifiants et pour terminer EditiX !

Le nombre d’occurrences

Dans le chapitre précédent, nous avons vu comment écrire des éléments de type complexe. Je peux maintenant vous avouer que je vous ai caché quelques petites choses. 😉 Nous allons les découvrir ensemble dès à présent.

La première concerne le nombre d’occurrences d’une balise. Pour vous aider à bien comprendre cette notion, je vous propose d’étudier un morceau de Schéma XML que nous avons déjà vu. Il s’agit de celui d’une personne qui possède un nom et un prénom :

<xsd:element name="personne"> 
  <xsd:complexType> 
    <xsd:sequence> 
      <xsd:element name="nom" type="xsd:string" />
      <xsd:element name="prenom" type="xsd:string" />
    </xsd:sequence> 
  </xsd:complexType> 
</xsd:element>

Comme je vous le disais précédemment, cet extrait signifie que la balise <personne /> contient les balises <nom /> et <prenom /> dans cet ordre.

La notion d’occurrence va nous permettre de préciser si les balises, dans le cas de notre exemple <nom /> et <prenom />, peuvent apparaître plusieurs fois, voire pas du tout.

Le cas par défaut

Le cas par défaut est celui que nous avons vu jusqu’à maintenant. Lorsque le nombre d’occurrences n’est pas précisé, la balise doit apparaître une et une seule fois.

Le nombre minimum d’occurrences

Pour indiquer le nombre minimum d’occurrences d’un élément, on utilise l’attributminOccurs. Comme nous l’avons déjà vu plus haut, sa valeur par défaut est 1.

Le nombre maximum d’occurrences

Pour indiquer le nombre maximum d’occurrences d’un élément, on utilise l’attributmaxOccurs. Comme pour le nombre minimum d’occurrences, la valeur par défaut est 1. Une nouvelle fois, dans le cas où il est utilisé, sa valeur doit obligatoirement être supérieure à zéro.

Exemple

Je vous propose de terminer ce chapitre en l’illustrant par un exemple.

<xsd:element name="personne"> 
  <xsd:complexType> 
    <xsd:sequence> 
      <xsd:element name="nom" type="xsd:string" />
      <xsd:element name="prenom" type="xsd:string" minOccurs="2" maxOccurs="unbounded" />
    </xsd:sequence> 
  </xsd:complexType> 
</xsd:element>

Dans l’extrait de Schéma XML ci-dessus, on remarque que pour l’élémentprenom, le nombre minimum d’occurrences est à 2 tandis qu’il n’y a pas de maximum. Cela signifie, que dans notre fichier XML, cette balise devra apparaître entre 2 et une infinité de fois comme en témoigne les extraits de fichier XML suivants :

<personne>
  <nom>Zozor</nom>
  <prenom>Robert</prenom>
  <prenom>Bernard</prenom>
</personne>

<personne>
  <nom>Zozor</nom>
  <prenom>Robert</prenom>
  <prenom>Bernard</prenom>
  <prenom>Paul</prenom>
  <prenom>Pierre</prenom>
</personne>

La réutilisation des éléments

Avant d’attaquer la notion d’héritage, nous allons voir comment réutiliser des types complexes afin d’en écrire le moins possible. C’est bien connu, les informaticiens sont des fainéants ! 😉

Pourquoi ne pas tout écrire d’un seul bloc ?

Puisqu’un exemple est souvent bien plus parlant que de longues explications, je vous propose d’étudier le document XML suivant :

<?xml version="1.0" encoding="UTF-8"?>
<banque>
  <!-- 1er client de la banque -->
  <client>
    <!-- identité du client -->
    <identite>
      <nom>NORRIS</nom>
      <prenom>Chuck</prenom>
    </identite>

    <!-- liste des comptes bancaires du client -->
    <comptes>
      <livretA>
        <montant>2500</montant>
      </livretA>
      <courant>
        <montant>4000</montant>
      </courant>
    </comptes>
  </client>
</banque>

Ce document XML représente une banque et ses clients. Pour chaque client, on connaît son identité, le montant de son livret A ainsi que le montant de son compte courant.

Avec nos connaissances actuelles, voici ce à quoi ressemble le Schéma XML qui décrit ce document XML :

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="banque">
    <xsd:complexType >
      <xsd:sequence>
        <xsd:element name="client" maxOccurs="unbounded">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="identite">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="nom" type="xsd:string" />
                    <xsd:element name="prenom" type="xsd:string" />
                  </xsd:sequence>
                </xsd:complexType>
              </xsd:element>
              <xsd:element name="comptes">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="livretA">
                      <xsd:complexType>
                        <xsd:sequence>
                          <xsd:element name="montant" type="xsd:double" />
                        </xsd:sequence>         
                      </xsd:complexType>
                    </xsd:element>
                    <xsd:element name="courant">
                      <xsd:complexType>
                        <xsd:sequence>
                          <xsd:element name="montant" type="xsd:double" />
                        </xsd:sequence>         
                      </xsd:complexType>
                    </xsd:element>
                  </xsd:sequence>
                </xsd:complexType>
              </xsd:element>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>  
  </xsd:element>
</xsd:schema>

Cette construction d’un seul bloc, également appelé construction “en poupées russes” n’est pas des plus lisibles. Afin de rendre notre Schéma XML un peu plus clair et compréhensible, je vous propose de le diviser. Sa lecture en sera grandement facilitée.

Diviser un Schéma XML

Quelques explications

Dans cette partie nous allons voir comment “casser” cette écriture “en poupées russes” afin de rendre notre Schéma XML plus compréhensible et plus accessible.

L’idée est assez simple dans son ensemble. On déclare de manière globale les différents éléments qui composent notre Schéma XML, puis, dans nos structures complexes, on y fait référence.

La syntaxe

La déclaration d’un élément ne change pas par rapport à ce que nous avons vu jusqu’à maintenant, qu’il s’agisse d’un élément simple ou d’un élément complexe.

Établir une référence est alors très simple grâce au mot clef ref :

<xsd:element ref="mon_nom" />

Je vous propose d’illustrer l’utilisation de ce nouveau mot clef via un exemple. Nous allons décomposer l’identité d’un client. Pour rappel, voici ce que nous avons écrit dans notre premier essai :

<xsd:element name="identite" >
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element name="nom" type="xsd:string" />
      <xsd:element name="prenom" type="xsd:string" />
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>

Nous allons donc faire une déclaration globale des éléments nom et prenom afin d’y faire référence dans l’élément complexe identite.

<!-- déclaration globale de certains éléments -->
<xsd:element name="nom" type="xsd:string" />
<xsd:element name="prenom" type="xsd:string" />

<xsd:element name="identite" >
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element ref="nom" />
      <xsd:element ref="prenom" />
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>

Comme vous pouvez le constater, l’ensemble est déjà plus lisible. Cette méthode nous permet également de réutiliser des éléments qui reviennent plusieurs fois comme par exemple l’élément montant présent dans le compte courant et le livret A d’un client.

Mise à jour de notre banque et ses clients

Mettons alors à jour notre Schéma XML afin de le découper le plus possible :

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <!-- déclaration des éléments -->
  <xsd:element name="nom" type="xsd:string" />
  <xsd:element name="prenom" type="xsd:string" />
  <xsd:element name="montant" type="xsd:double" />

  <xsd:element name="banque">
    <xsd:complexType >
      <xsd:sequence>
        <xsd:element name="client" maxOccurs="unbounded">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="identite">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element ref="nom" />
                    <xsd:element ref="prenom" />
                  </xsd:sequence>
                </xsd:complexType>
              </xsd:element>
              <xsd:element name="comptes">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="livretA">
                      <xsd:complexType>
                        <xsd:sequence>
                          <xsd:element ref="montant" />
                        </xsd:sequence>         
                      </xsd:complexType>
                    </xsd:element>
                    <xsd:element name="courant">
                      <xsd:complexType>
                        <xsd:sequence>
                          <xsd:element ref="montant" />
                        </xsd:sequence>         
                      </xsd:complexType>
                    </xsd:element>
                  </xsd:sequence>
                </xsd:complexType>
              </xsd:element>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>  
  </xsd:element>
</xsd:schema>

Comme vous pouvez le constater, c’est mieux, mais selon moi, ce n’est pas encore ça. Plutôt que de déclarer globalement uniquement des éléments simples comme le montant, le nom ou le prenom, pourquoi ne pas déclarer globalement des éléments complexes comme l’identité du client ou encore le livret A ou le compte courant.

Voyons alors le résultat :

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <!-- déclaration des éléments -->
  <xsd:element name="montant" type="xsd:double" />

  <xsd:element name="identite">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="nom" type="xsd:string" />
        <xsd:element name="prenom" type="xsd:string" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

  <xsd:element name="livretA">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="montant" />
      </xsd:sequence>           
    </xsd:complexType>
  </xsd:element>

  <xsd:element name="courant">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="montant" />
      </xsd:sequence>           
    </xsd:complexType>
  </xsd:element>

  <xsd:element name="comptes">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="livretA" />
        <xsd:element ref="courant" />
      </xsd:sequence>
    </xsd:complexType>
   </xsd:element>

  <xsd:element name="client">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="identite" />
        <xsd:element ref="comptes" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

  <!-- Schéma XML -->
  <xsd:element name="banque">
    <xsd:complexType >
      <xsd:sequence>
        <xsd:element ref="client" maxOccurs="unbounded" />
      </xsd:sequence>
    </xsd:complexType>  
  </xsd:element>
</xsd:schema>

C’est tout de même plus lisible, non ? 😉

Créer ses propres types

Grâce aux références, nous sommes arrivés à un résultat satisfaisant, mais si l’on regarde en détail, on se rend vite compte que notre Schéma XML n’est pas optimisé. En effet, les différents comptes de notre client, à savoir le livret A et le compte courant, ont des structures identiques et pourtant, nous les déclarons 2 fois.

Dans cette partie, nous allons donc apprendre à créer nos propres types pour encore et toujours en écrire le moins possible !

La syntaxe

Déclarer un nouveau type, n’est pas plus compliqué que ce que nous avons vu jusqu’à présent. Il est cependant important de noter une petite chose. Les types que nous allons créer peuvent être de 2 natures : simple ou complexe.

Débutons avec la création et l’utilisation d’un type simple. La création d’un type simple est utile lorsque par exemple dans un Schéma XML, plusieurs chaînes de caractères ou plusieurs nombres ont des restrictions similaires.

<!-- création -->
<xsd:simpleType name="mon_type_perso">
  <xsd:restriction base="mon_type">
    <!-- liste des restrictions -->
  </xsd:restriction>
</xsd:simpleType>

<!-- utilisation-->
<xsd:element name="mon_nom" type="mon_type_perso" />

Continuons avec la création et l’utilisation d’un type complexe :

<!-- création -->
<xsd:complexType name="mon_type_perso">
  <!-- personnalisation du type complexe -->
</xsd:complexType>

<!-- utilisation-->
<xsd:element name="mon_nom" type="mon_type_perso" />

Mise à jour de notre banque et ses clients

Je vous propose de mettre à jour notre Schéma XML en créant un type “compte” que l’on pourra utiliser pour le livret A et le compte courant des clients de notre banque.

Voici alors ce que ça donne :

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <!-- déclaration des éléments -->
  <xsd:element name="montant" type="xsd:double" />

  <xsd:element name="identite" >
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="nom" type="xsd:string" />
        <xsd:element name="prenom" type="xsd:string" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

  <xsd:complexType name="compte">
    <xsd:sequence>
      <xsd:element ref="montant" />
    </xsd:sequence>         
  </xsd:complexType>

  <xsd:element name="comptes">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="livretA" type="compte" />
        <xsd:element name="courant" type="compte" />
      </xsd:sequence>
    </xsd:complexType>
   </xsd:element>

  <xsd:element name="client">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="identite" />
        <xsd:element ref="comptes" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

  <!-- Schéma XML -->
  <xsd:element name="banque">
    <xsd:complexType >
      <xsd:sequence>
        <xsd:element ref="client" maxOccurs="unbounded" />
      </xsd:sequence>
    </xsd:complexType>  
  </xsd:element>
</xsd:schema>

Notre Schéma XML est bien plus lisible maintenant ! 😉

L’héritage

L’héritage est un concept que l’on retrouve dans la plupart des langages de programmation orienté objet. Certes le XML n’est pas un langage de programmation, mais ça ne l’empêche pas d’assimiler cette notion.

Pour faire simple, l’héritage permet de réutiliser des éléments d’un Schéma XML pour en construire de nouveaux. Si vous avez encore du mal à comprendre le concept, ne vous inquiétez pas, nous allons utiliser des exemples afin de l’illustrer.

En XML, 2 types d’héritages sont possibles :

  • Par restriction.
  • Par extension.

Dans les 2 cas, c’est le mot clef base que nous utiliserons pour indiquer un héritage.

L’héritage par restriction

La première forme d’héritage que nous allons voir est celle par restriction.

Définition

Une restriction est une notion qui peut s’appliquer aussi bien aux éléments qu’aux attributs et qui permet de déterminer plus précisément la valeur attendue via la détermination d’un certain nombre de contraintes.

Par exemple, jusqu’à maintenant, nous sommes capables de dire qu’un élément ou qu’un attribut doit contenir un nombre entier strictement positif. Grâce aux restrictions, nous allons pouvoir pousser le concept jusqu’au bout en indiquant qu’un élément ou qu’un attribut doit contenir un nombre entier strictement positif compris entre 1 et 100.

Lorsque l’on déclare une restriction sur un élément, la syntaxe suivante doit être respectée :

<xsd:element name="mon_nom">
  <xsd:simpleType>
    <xsd:restriction base="type_de_base">
      <!-- détail de la restriction -->
    </xsd:restriction>
  </xsd:simpleType>
</xsd:element>

La syntaxe est quasiment identique dans le cas d’un attribut :

<xsd:attribute name="mon_nom">
  <xsd:simpleType>
    <xsd:restriction base="type_de_base">
      <!-- détail de la restriction -->
    </xsd:restriction>
  </xsd:simpleType>
</xsd:attribute>

Vous avez très probablement remarqué l’attribut base dans la balise <restriction />. Il s’agit du type de votre balise et donc de votre restriction. Il suffit donc de choisir un type simple dans la liste de ceux que nous avons vu dans les chapitres précédents (xsd:string, xsd:int, etc.).

Le tableau récapitulatif

Type Description
minExclusive permet de définir une valeur minimale exclusive
minInclusive permet de définir une valeur minimale inclusive
maxExclusive permet de définir une valeur maximale exclusive
maxInclusive permet de définir une valeur maximale inclusive
totalDigits permet de définir le nombre exact de chiffres qui composent un nombre
fractionDigits permet de définir le nombre de chiffres autorisés après la virgule
length permet de définir le nombre exact de caractères d'une chaîne
minLength permet de définir le nombre minimum de caractères d'une chaîne
maxLength permet de définir le nombre maximum de caractères d'une chaîne
enumeration permet d'énumérer la liste des valeurs possibles
whiteSpace permet de déterminer le comportement à adopter avec les espaces
pattern permet de définir des expressions rationnelles

Plus en détails

La restriction minExclusive

La restriction minExclusive s’applique à un élément de type numérique et permet de définir sa valeur minimale. Comme son nom le laisse deviner, la valeur indiquée est exclue des valeurs que peut prendre l’élément.

Voici sa syntaxe :

<xsd:element name="mon_nom">
  <xsd:simpleType>
    <xsd:restriction base="type_de_base">
      <xsd:minExclusive value="ma_valeur" />
    </xsd:restriction>
  </xsd:simpleType>
</xsd:element>

Afin d’illustrer cette première restriction, prenons par exemple l’âge d’une personne que l’on souhaite obligatoirement majeure :

<xsd:complexType name="personne">
  <xsd:attribute name="age">
    <xsd:simpleType>
      <xsd:restriction base="xsd:nonNegativeInteger">
        <xsd:minExclusive value="17" />
      </xsd:restriction>
    </xsd:simpleType>
  </xsd:attribute>
</xsd:complexType>
<!-- valide -->
<personne age="18" />

<!-- valide -->
<personne age="43" />

<!-- invalide -->
<personne age="17" />
La restriction minInclusive

La restriction minInclusive ressemble énormément à la restriction minExclusive que nous venons de voir si ce n’est que la valeur indiquée peut-être prise par l’élément.

Voici sa syntaxe :

<xsd:element name="mon_nom">
  <xsd:simpleType>
    <xsd:restriction base="type_de_base">
      <xsd:minInclusive value="ma_valeur" />
    </xsd:restriction>
  </xsd:simpleType>
</xsd:element>
La restriction maxExclusive

La restriction maxExclusive s’applique à un élément de type numérique et permet de définir sa valeur maximale. Comme son nom le laisse deviner, la valeur indiquée est exclue des valeurs que peut prendre l’élément.

Voici sa syntaxe :

<xsd:element name="mon_nom">
  <xsd:simpleType>
    <xsd:restriction base="type_de_base">
      <xsd:maxExclusive value="ma_valeur" />
    </xsd:restriction>
  </xsd:simpleType>
</xsd:element>
La restriction maxInclusive

La restriction maxInclusive ressemble énormément à la restriction maxExclusive que nous venons de voir si ce n’est que la valeur indiquée peut-être prise par l’élément.

Voici sa syntaxe :

<xsd:element name="mon_nom">
  <xsd:simpleType>
    <xsd:restriction base="type_de_base">
      <xsd:maxInclusive value="ma_valeur" />
    </xsd:restriction>
  </xsd:simpleType>
</xsd:element>
La restriction totalDigits

La restriction totalDigits s’applique à un élément de type numérique et permet de définir le nombre exact de chiffres qui composent le nombre. Sa valeur doit obligatoirement être supérieure à zéro.

Voici sa syntaxe :

<xsd:element name="mon_nom">
  <xsd:simpleType>
    <xsd:restriction base="type_de_base">
      <xsd:totalDigits value="ma_valeur" />
    </xsd:restriction>
  </xsd:simpleType>
</xsd:element>

Je vous propose d’illustrer tout de suite cette restriction avec un exemple. Une nouvelle fois prenons l’âge d’une personne. Imaginons un contexte dans lequel l’âge d’une personne doit obligatoirement être compris entre 10 et 99. Il doit donc être obligatoirement composé de 2 chiffres :

<xsd:complexType name="personne">
  <xsd:attribute name="age">
    <xsd:simpleType>
      <xsd:restriction base="xsd:nonNegativeInteger">
        <xsd:totalDigits value="2" />
      </xsd:restriction>
    </xsd:simpleType>
  </xsd:attribute>
</xsd:complexType>
<!-- valide -->
<personne age="18" />

<!-- valide -->
<personne age="43" />

<!-- invalide -->
<personne age="4" />
La restriction fractionDigits

La restriction fractionDigits s’applique à un élément de type numérique et permet de définir le nombre maximal de chiffres qui composent une décimale. Sa valeur peut-être supérieure ou égale à zéro.

Voici sa syntaxe :

<xsd:element name="mon_nom">
  <xsd:simpleType>
    <xsd:restriction base="type_de_base">
      <xsd:fractionDigits value="ma_valeur" />
    </xsd:restriction>
  </xsd:simpleType>
</xsd:element>
La restriction length

La restriction length permet de définir le nombre exact de caractères qui composent une chaîne. La valeur renseignée doit obligatoirement être supérieure ou égale à zéro.

Voici sa syntaxe :

<xsd:element name="mon_nom">
  <xsd:simpleType>
    <xsd:restriction base="type_de_base">
      <xsd:length value="ma_valeur" />
    </xsd:restriction>
  </xsd:simpleType>
</xsd:element>

Pour illustrer l’utilisation de la restriction length, prenons par exemple une empreinte SHA1. Pour faire simple, une empreinte SHA1 est un nombre hexadécimal composé de 40 caractères :

<xsd:complexType name="sha1">
  <xsd:simpleType>
    <xsd:restriction base="xsd:hexBinary">
      <xsd:length value="40" />
    </xsd:restriction>
  </xsd:simpleType>
</xsd:complexType>
<!-- valide -->
<sha1>edf7a6029d6bdfb68447677a1d76639725f795f1</sha1>

<!-- valide -->
<sha1>a94a8fe5ccb19ba61c4c0873d391e987982fbbd3</sha1>

<!-- invalide -->
<sha1>test</sha1>
La restriction minLength

La restriction minLength permet de définir le nombre minimum de caractères qui composent une chaîne. La valeur renseignée doit obligatoirement être supérieure ou égale à zéro.

Voici sa syntaxe :

<xsd:element name="mon_nom">
  <xsd:simpleType>
    <xsd:restriction base="type_de_base">
      <xsd:minLength value="ma_valeur" />
    </xsd:restriction>
  </xsd:simpleType>
</xsd:element>
La restriction maxLength

La restriction maxLength permet de définir le nombre maximum de caractères qui composent une chaîne. La valeur renseignée doit obligatoirement être supérieure ou égale à zéro.

Voici sa syntaxe :

<xsd:element name="mon_nom">
  <xsd:simpleType>
    <xsd:restriction base="type_de_base">
      <xsd:maxLength value="ma_valeur" />
    </xsd:restriction>
  </xsd:simpleType>
</xsd:element>
La restriction enumeration

La restriction enumeration, comme son nom le laisse deviner, cette restriction permet d’énumérer la liste des valeurs possibles pour un élément ou un attribut.

Voici sa syntaxe :

<xsd:element name="mon_nom">
  <xsd:simpleType>
    <xsd:restriction base="type_de_base">
      <xsd:enumeration value="valeur1" />
      <xsd:enumeration value="valeur2" />
      <!-- liste des valeurs... -->
    </xsd:restriction>
  </xsd:simpleType>
</xsd:element>

Afin d’illustrer cette restriction, prenons l’exemple d’une personne comme nous l’avons déjà fait à plusieurs reprises dans ce tutoriel. Une personne possède un nom, un prénom, et est normalement un homme ou une femme. Écrivons alors la règle d’un Schéma XML permettant de décrire une personne :

<xsd:complexType name="personne">
  <xsd:sequence>
    <xsd:element name="nom" type="xsd:string" />
    <xsd:element name="prenom" type="xsd:string" />
  </xsd:sequence>
  <xsd:attribute name="sexe">
    <xsd:simpleType>
      <xsd:restriction base="xsd:string">
        <xsd:enumeration value="masculin" />
        <xsd:enumeration value="feminin" />
      </xsd:restriction>
    </xsd:simpleType>
  </xsd:attribute>
</xsd:complexType>
<!-- valide -->
<personne sexe="masculin">
  <nom>DUPONT</nom>
  <prenom>Robert</prenom>
</personne>

<!-- valide -->
<personne sexe="feminin">
  <nom>DUPONT</nom>
  <prenom>Robert</prenom>
</personne>

<!-- invalide -->
<personne sexe="pomme">
  <nom>DUPONT</nom>
  <prenom>Robert</prenom>
</personne>
La restriction whiteSpace

La restriction whiteSpace permet de spécifier le comportement à adopter par un élément lorsqu’il contient des espaces. Les espaces peuvent être de différentes formes comme par exemple les tabulations, les retours à la ligne, etc.

3 valeurs sont possibles :

  • Preserve : cette valeur permet de préserver tous les espaces.
  • Replace : cette valeur permet de remplacer tous les espaces (tabulations, retour à la ligne, etc.) par des espaces “simples”.
  • Collapse : cette valeur permet de supprimer les espaces en début et fin de chaîne, de remplacer les tabulations et les retours à la ligne par un espace “simple” et de remplacer les espaces multiples par un espace “simple”.

Voici sa syntaxe :

<xsd:element name="mon_nom">
  <xsd:simpleType>
    <xsd:restriction base="type_de_base">
      <xsd:whiteSpace value="ma_valeur" />
    </xsd:restriction>
  </xsd:simpleType>
</xsd:element>
La restriction pattern

La restriction pattern permet de définir des expressions rationnelles (également appelées expressions régulières). Une expression rationnelle est un motif qui permet de décrire le contenu attendu. Ainsi à l’aide des expressions rationnelles, il est possible de dire que le contenu attendu doit forcément débuter par une majuscule, se terminer par un point, débuter par un caractère spécial, ne pas contenir la lettre “z”, etc.

Les expressions rationnelles sont un langage à part entière sur lequel nous n’allons pas revenir dans ce cours, mais ne vous inquiétez pas, vous trouverez facilement sur Internet de nombreuses ressources francophones sur le sujet.

Voici sa syntaxe :

<xsd:element name="mon_nom">
  <xsd:simpleType>
    <xsd:restriction base="type_de_base">
      <xsd:pattern value="ma_valeur" />
    </xsd:restriction>
  </xsd:simpleType>
</xsd:element>

Afin d’illustrer cette dernière restriction, prenons l’exemple du prénom non composé d’une personne. On souhaite qu’il débute par une majuscule et soit suivi par plusieurs caractères minuscules :

<xsd:complexType name="prenom">
  <xsd:simpleType>
    <xsd:restriction base="xsd:string">
      <xsd:pattern value="[A-Z][a-z]+" />
    </xsd:restriction>
  </xsd:simpleType>
</xsd:complexType>
<!-- valide -->
<prenom>Robert</prenom>

<!-- valide -->
<prenom>Zozor</prenom>

<!-- invalide -->
<prenom>bernard</prenom>

L’héritage par extension

Dans cette seconde partie, nous allons voir le second type d’héritage : l’héritage par extension.

Définition

Une extension est une notion qui permet d’ajouter des informations à un type existant. On peut, par exemple, vouloir ajouter un élément ou un attribut.

Lorsque l’on déclare une extension sur un élément, c’est toujours le mot clef base qui est utilisé :

<!-- contenu complexe -->
<xsd:complexType name="mon_nom">
  <xsd:complexContent>
    <xsd:extension base="type_de_base">
      <!-- détail de l'extension -->
    </xsd:extension>
  </xsd:complexContent>
</xsd:complexType>

<!-- contenu simple -->
<xsd:complexType name="mon_nom"> 
  <xsd:simpleContent> 
    <xsd:extension base="type_de_base"> 
      <!-- détail de l'extension --> 
    </xsd:extension> 
  </xsd:simpleContent> 
</xsd:complexType>

Exemple

Je vous propose de mettre en application cette nouvelle notion d’héritage par extension au travers d’un exemple. Reprenons les données clientes d’une banque que nous manipulions dans le chapitre précédent. Dans cet exemple, nous avions défini un type “compte” appliqué au compte courant et au livret A de notre client :

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <!-- déclaration des éléments -->
  <xsd:element name="montant" type="xsd:double" />

  <xsd:element name="identite">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="nom" type="xsd:string" />
        <xsd:element name="prenom" type="xsd:string" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

  <xsd:complexType name="compte">
    <xsd:sequence>
      <xsd:element ref="montant" />
    </xsd:sequence>         
  </xsd:complexType>

  <xsd:element name="comptes">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="livretA" type="compte" />
        <xsd:element name="courant" type="compte" />
      </xsd:sequence>
    </xsd:complexType>
   </xsd:element>

  <xsd:element name="client">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="identite" />
        <xsd:element ref="comptes" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

  <!-- Schéma XML -->
  <xsd:element name="banque">
    <xsd:complexType >
      <xsd:sequence>
        <xsd:element ref="client" maxOccurs="unbounded" />
      </xsd:sequence>
    </xsd:complexType>  
  </xsd:element>
</xsd:schema>

Imaginons maintenant que le compte courant et le livret A soient un peu différents. Par exemple, un compte courant n’a généralement pas de taux d’intérêts tandis que le livret A en a un. Malgré ce petit changement, le livret A et le compte courant restent sensiblement identiques. C’est là que l’héritage par extension intervient. Nous allons étendre le type compte en y ajoutant un attribut pour créer ainsi un nouveau type : celui d’un compte avec des intérêts.

<!-- le montant -->
<xsd:element name="montant" type="xsd:double" />

<!-- compte sans intérêts -->
<xsd:complexType name="compte">
  <xsd:sequence>
    <xsd:element ref="montant" />
  </xsd:sequence>           
</xsd:complexType>

<!-- compte avec intérêts grâce à l'héritage par extension -->
<xsd:complexType name="compteInteret">
  <xsd:complexContent>
    <xsd:extension base="compte">
      <xsd:attribute name="interet" type="xsd:float" />
    </xsd:extension>
  </xsd:complexContent>         
</xsd:complexType>

Les identifiants

Nous avons déjà vu que dans un Schéma XML, il est possible d’identifier des ressources et d’y faire référence grâce aux mots clefs ID et IDREF.

Il est cependant possible d’aller plus loin et d’être encore plus précis grâce à 2 nouveaux mots clefs : key et keyref.

La syntaxe

L’élément key

Au sein d’un Schéma XML, l’élément <key /> est composé :

  • D’un élément <selector /> contenant une expression XPath afin d’indiquer l’élément à référencer.
  • D’un ou plusieurs éléments <field /> contenant une expression XPath afin d’indiquer l’attribut servant d’identifiant.

Ce qui nous donne :

<xsd:key name="nom_identifiant">
  <selector xpath="expression_XPath" />
  <!-- liste d'éléments field -->
  <field xpath="expression_XPath" />
</xsd:key>

L’élément keyref

L’élément <keyref /> se construit sensiblement comme l’élément <key />. Il est donc composé :

  • D’un élément <selector /> contenant une expression XPath afin d’indiquer l’élément à référencer.
  • D’un ou plusieurs éléments <field /> contenant une expression XPath afin d’indiquer l’attribut servant d’identifiant.

Ce qui nous donne :

<xsd:keyref name="nom" refer="nom_identifiant">
  <selector xpath="expression_XPath" />
  <!-- liste d'éléments field -->
  <field xpath="expression_XPath" />
</xsd:keyref>

Exemple

Afin d’illustrer cette nouvelle notion, je vous propose d’étudier le document XML suivant :

<famille>
  <pere id="PER-1" />
  <enfant id="PER-2" pere="PER-1" />
</famille>

Dans cet exemple, une famille est composée d’un père et d’un enfant dont chacun possède un identifiant unique au travers de l’attribut id. L’enfant possède également un attribut pere qui contient l’identifiant de son père.

Je vous propose de construire ensemble le Schéma XML qui correspond au document XML. Commençons par décrire l’élément <pere /> :

<xsd:element name="pere">
  <xsd:complexType>
    <xsd:attribute name="id" type="xsd:NCName" />
  </xsd:complexType>
</xsd:element>

Continuons avec l’élément <enfant /> :

<xsd:element name="enfant">
  <xsd:complexType>
    <xsd:attribute name="id" type="xsd:NCName" />
    <xsd:attribute name="pere" type="xsd:NCName" />
  </xsd:complexType>
</xsd:element>

Terminons avec l’élément <famille /> :

<xsd:element name="famille">
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element ref="pere" />
      <xsd:element ref="enfant" />
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>

Modifions ce dernier élément afin d’y ajouter nos identifiants. Pour le moment, je vous demande d’accepter les expressions XPath présentes dans le Schéma XML. Dans la partie suivante, vous serez normalement en mesure de les comprendre.

<xsd:element name="famille">
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element ref="pere" />
      <xsd:element ref="enfant" />
    </xsd:sequence>
  </xsd:complexType>

  <!-- identifiant du père -->
  <xsd:key name="pereId">
    <xsd:selector xpath="./pere" />
    <xsd:field xpath="@id" />
  </xsd:key>

  <!-- identifiant de l'enfant -->
  <xsd:key name="enfantId">
    <xsd:selector xpath="./enfant" />
    <xsd:field xpath="@id" />
  </xsd:key>

  <!-- référence à l'identifiant du père dans l'élément enfant -->
  <xsd:keyref name="pereIdRef" refer="pereId">
    <xsd:selector xpath="./enfant" />
    <xsd:field xpath="@pere" />
  </xsd:keyref>
</xsd:element>

Un exemple avec EditiX

Pour conclure ce chapitre, je vous propose de voir ensemble comment écrire un Schéma XML avec EditiX.

Pour faire simple, reprenons l’exemple de notre banque vu dans le chapitre sur la réutilisation des types.

Création du document XML

La création du document XML n’a rien de bien compliqué, nous l’avons déjà vu ensemble dans la partie précédente.

Pour ceux qui ne s’en souviennent pas, vous pouvez y jeter un coup d’œil ici.

Voici le document que vous devez écrire :

<?xml version="1.0" encoding="UTF-8"?>
<banque xsi:noNamespaceSchemaLocation="banque.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <!-- 1er client de la banque -->
  <client>
    <!-- identité du client -->
    <identite>
      <nom>NORRIS</nom>
      <prenom>Chuck</prenom>
    </identite>

    <!-- liste des comptes bancaires du client -->
    <comptes>
      <livretA>
        <montant>2500</montant>
      </livretA>
      <courant>
        <montant>4000</montant>
      </courant>
    </comptes>
  </client>
</banque>

Si vous essayez de lancer la vérification du document, vous devriez normalement avoir le message d’erreur suivant (voir la figure suivante).

Message d'erreur indiquant que le Schéma XML est introuvable

Ce message est pour le moment complètement normal puisque nous n’avons pas encore créé notre document XSD.

Création du document XSD

Pour créer un nouveau document, vous pouvez sélectionner dans la barre de menu File puis New ou encore utiliser le raccourci clavier Ctrl + N.

Dans la liste qui s’affiche, sélectionnez W3C XML Schema, ainsi qu’indiqué sur la figure suivante.

Création d'un Schéma XML

Votre document XSD n’est normalement pas vierge. Voici ce que vous devriez avoir :

<?xml version="1.0" encoding="UTF-8"?>

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

</xs:schema>

Remplacez le contenu par notre véritable Schéma XML :

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <!-- déclaration des éléments -->
  <xsd:element name="montant" type="xsd:double" />

  <xsd:element name="identite" >
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="nom" type="xsd:string" />
        <xsd:element name="prenom" type="xsd:string" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

  <xsd:complexType name="compte">
    <xsd:sequence>
      <xsd:element ref="montant" />
    </xsd:sequence>         
  </xsd:complexType>

  <xsd:element name="comptes">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="livretA" type="compte" />
        <xsd:element name="courant" type="compte" />
      </xsd:sequence>
    </xsd:complexType>
   </xsd:element>

  <xsd:element name="client">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="identite" />
        <xsd:element ref="comptes" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

  <!-- Schéma XML -->
  <xsd:element name="banque">
    <xsd:complexType >
      <xsd:sequence>
        <xsd:element ref="client" maxOccurs="unbounded" />
      </xsd:sequence>
    </xsd:complexType>  
  </xsd:element>
</xsd:schema>

Enregistrez ensuite votre document avec le nom banque.xsd au même endroit que votre document XML.

Vérification du Schéma XML

Vous pouvez vérifier que votre Schéma XML n’a pas d’erreur de syntaxe en cliquant sur l’icône

Icône editix check document

ou en sélectionnant dans la barre de menu XML puis Check this document ou encore en utilisant le raccourci clavier Ctrl + K.

Vous devriez normalement avoir le message suivant (voir la figure qui suit).

Message indiquant que le Schéma XML ne contient aucune erreur de syntaxe

Vérification du document XML

Il est maintenant temps de vérifier que le document XML est valide !

Pour ce faire, cliquez sur l’icône

Icône editix check document

ou sélectionnez dans la barre de menu XML puis Check this document ou utilisez le raccourci clavier Ctrl + K.

Le message suivant doit normalement s’afficher (voir la figure suivante).

Message indiquant que le document XML est valide

En résumé

  • Le nombre d’occurrences d’un élément s’exprime grâce aux mots clefs minOccurs et maxOccurs.
  • Le mot clef ref permet de faire référence à des éléments dans le but de les réutiliser plusieurs fois au sein du Schéma XML.
  • L’héritage permet de réutiliser des éléments d’un Schéma XML pour en construire de nouveaux.
  • Il existe 2 types d’héritages : l’héritage par restriction et l’héritage par extension.

Ce cours vous plait ?

Retrouvez ce cours en livre physique sur Amazon !