Les schémas XML permettent, comme les DTD, de définir des modèles de documents. Il est ensuite possible de vérifier qu'un document donné est valide pour un schéma, c'est-à-dire respecte les contraintes données par le schéma. Les schémas ont été introduits pour combler certaines lacunes des DTD.
La première différence entre les schémas et les DTD est d'ordre
syntaxique. La syntaxe des DTD est une syntaxe héritée de SGML qui est
différente de la syntaxe XML pour le corps des documents. En revanche,
la syntaxe des schémas est une syntaxe purement XML. Un schéma est, en
effet, un document XML à part entière avec un élément racine
xsd:schema
et un espace de noms.
Les DTD manquent cruellement de précision dans la description des
contenus des éléments. Cette lacune se manifeste surtout au niveau des
contenus textuels et des contenus mixtes. Il est, par exemple,
impossible d'imposer des contraintes sur les contenus textuels des éléments.
Le seul type possible pour les contenus textuels est
#PCDATA
qui autorise toutes les chaînes de
caractères. Les types pour les attributs sont un peu plus nombreux mais
ils restent encore très limités. À l'inverse, les schémas possèdent une
multitude de types
prédéfinis pour les contenus textuels. Ces types couvrent les
chaînes de caractères, les nombres comme les entiers et les flottants
ainsi que les heures et les dates. Ces types peuvent, en outre, être
affinés par des mécanismes de restriction et d'union. Il est possible
de définir, à titre d'exemple, des types pour les entiers entre
1
et 12
, les flottants avec deux
décimales ou les chaînes d'au plus 16 caractères ne comportant que des
chiffres et des tirets '-'
.
Les DTD sont encore plus limitées dans la description des contenus mixtes. La seule possibilité est d'exprimer que le contenu d'un élément est un mélange, sans aucune contrainte, de texte et de certains éléments. Les schémas comblent cette lacune en permettant d'avoir des contenus mixtes aussi précis que les contenus purs qui décrivent l'ordre et les nombres d'occurrences des enfants d'un élément.
Dans une DTD, le contenu pur d'un élément est décrit directement par une expression rationnelle. Les schémas procèdent en deux étapes. Ils définissent des types qui sont ensuite associés aux éléments. Les schémas se distinguent des DTD par leurs possibilités de définir de nouveaux types. Il est d'abord possible de construire des types explicitement à la manière des DTD. Il existe ensuite des mécanismes permettant de définir un nouveau type à partir d'un autre type, soit prédéfini, soit déjà défini dans le schéma. Ce nouveau type est obtenu soit par extension soit par restriction du type de départ. L'extension consiste à enrichir le type en ajoutant du contenu et des attributs. La restriction consiste, à l'inverse, à ajouter des contraintes pour restreindre les contenus valides. Ces deux mécanismes permettent ainsi de construire une véritable hiérarchie de types semblable à l'approche orientée objet des langages comme Java ou C++.
Les schémas autorisent des facilités impossibles avec les DTD. La première est la possibilité d'avoir plusieurs éléments locaux avec des noms identiques mais avec des types et donc des contenus différents. Dans une DTD, un élément a une seule déclaration qui décrit ses contenus possibles pour toutes ses occurrences dans un document. Une deuxième facilité est formée des mécanismes de substitution de types et d'éléments. À titre d'exemple, un schéma peut prévoir qu'un élément puisse se substituer à un autre élément. Ces substitutions fonctionnent de pair avec la hiérarchie des types.
Les DTD ont une modularité très limitée et l'écriture de DTD d'envergure est un exercice difficile. Les seuls dispositifs mis à disposition des auteurs de DTD sont l'import de DTD externes et les entités paramètres. Les schémas possèdent plusieurs mécanismes destinés à une plus grande modularité. Le premier d'entre eux est la possibilité, pour les schémas, de définir des types par extension et restriction. Il existe également les groupes d'éléments et les groupes d'attributs.
Les DTD proviennent de SGML et sont antérieures aux espaces de noms. Pour cette raison, elles ne les prennent pas en compte. La déclaration d'un élément se fait en donnant le nom qualifié de l'élément avec le préfixe et le nom local. Ceci impose, dans les documents, d'associer l'espace de noms à ce même préfixe. Ceci est contraire à l'esprit des espaces de noms où le préfixe est juste une abréviation interchangeable pour l'URI de l'espace de noms. Les schémas, au contraire, prennent en compte les espaces de noms. Un schéma déclare d'abord un espace de noms cible. Les éléments et les attributs sont ensuite déclarés, dans le schéma, avec leur nom local. Un document qui mélange des éléments et des attributs provenant d'espaces de noms différents peut encore être validé à l'aide des différents schémas pour les espaces de noms.
Voici un exemple de schéma XML définissant le type de document de la bibliographie. Ce schéma est volontairement rudimentaire pour un premier exemple. Il n'est pas très précis sur les contenus de certains éléments. Un exemple plus complet pourrait être donné pour la bibliographie.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:annotation>
<xsd:documentation xml:lang="fr"> Schéma XML pour bibliography.xml </xsd:documentation> </xsd:annotation> <xsd:element name="bibliography" type="Bibliography"/>
<xsd:complexType name="Bibliography">
<xsd:sequence> <xsd:element name="book" minOccurs="1" maxOccurs="unbounded">
<xsd:complexType> <xsd:sequence> <xsd:element name="title" type="xsd:string"/> <xsd:element name="author" type="xsd:string"/> <xsd:element name="year" type="xsd:string"/> <xsd:element name="publisher" type="xsd:string"/> <xsd:element name="isbn" type="xsd:string"/> <xsd:element name="url" type="xsd:string" minOccurs="0"/> </xsd:sequence> <xsd:attribute name="key" type="xsd:NMTOKEN" use="required"/>
<xsd:attribute name="lang" type="xsd:NMTOKEN" use="required"/>
</xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:schema>
Élément racine | |
Documentation du schéma. | |
Déclaration de l'élément | |
Début de la définition du type
| |
Déclaration de l'élément | |
Déclaration des attributs |
Ce schéma déclare l'élément bibliography
du type
Bibliography
qui est ensuite introduit par l'élément
xsd:complexType
. Ce type est alors défini comme une
suite d'autres éléments introduite par le constructeur
xsd:sequence
. Les deux attributs
key
et lang
de l'élément
book
sont introduits par les déclarations
xsd:attribute
.
Dans tout ce chapitre, la convention suivante est appliquée. Les
noms des éléments sont en minuscules alors que les noms des types
commencent par une majuscule comme les classes du langage Java. Les noms
de l'élément et de son type ne se différencient souvent que par la
première lettre comme bibliography
et
Bibliography
dans l'exemple précédent.
Comme pour les DTD, il existe des sites WEB permettant de valider
un document vis à vis d'un schéma. Cette validation peut également être
effectuée avec le logiciel xmllint
. L'option
--schema
permet de passer en paramètre un schéma en
plus du document XML.
Un schéma XML se compose essentiellement de déclarations d'éléments et d'attributs et de définitions de types. Chaque élément est déclaré avec un type qui peut être, soit un des types prédéfinis, soit un nouveau type défini dans le schéma. Le type spécifie quels sont les contenus valides de l'élément ainsi que ses attributs. Un nouveau type est obtenu soit par construction, c'est-à-dire une description explicite des contenus qu'il autorise, soit par dérivation, c'est-à-dire modification d'un autre type. Un schéma peut aussi contenir des imports d'autres schémas, des définitions de groupes d'éléments et d'attributs et des contraintes de cohérences.
L'espace de noms des schémas
XML est identifié par l'URI http://www.w3.org/2001/XMLSchema
.
Il est généralement associé, comme dans l'exemple précédent au préfixe
xsd
ou à xs
. Tout le schéma est
inclus dans l'élément xsd:schema
. La
structure globale d'un schéma est donc la suivante.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- Déclarations d'éléments, d'attributs et définitions de types --> ... </xsd:schema>
Les éléments, attributs et les types peuvent être
globaux ou locaux. Ils sont
globaux lorsque leur déclaration ou leur définition est un enfant direct
de l'élément racine xsd:schema
. Sinon, ils sont
locaux. Seuls les objets globaux peuvent être référencés dans tout le
schéma pour être utilisés. Dans le premier exemple de schéma donné
ci-dessus, l'élément bibliography
est global alors que
l'élément title
est local. La déclaration de ce
dernier intervient au sein de la définition du type
Bibliography
qui est global. Seuls les types globaux
d'un schéma sont nommés. Les types locaux sont anonymes et n'ont pas de
nom. Dans le schéma ci-dessus, le type de l'élément
book
est, par exemple, anonyme. Les éléments et
attributs sont toujours nommés, qu'ils soient globaux ou locaux. Ils
doivent, bien sûr, avoir un nom pour apparaître dans un document.
Les objets globaux et locaux se comportent différement vis à vis de
l'espace de noms cible du
schéma. Les objets globaux appartiennent toujours à cet espace de
noms. Les objets locaux, au contraire, appartiennent ou n'appartiennent
pas à l'espace de noms cible suivant les valeurs des attributs
form
, elementFormDefault
et
attributeFormDefault
.
Les éléments sont déclarés par l'élément
xsd:element
et les attributs par l'élément
xsd:attribute
. Les types sont définis par les
éléments xsd:simpleType
et
xsd:complexType
.
L'élément racine xsd:schema
peut avoir les
attributs suivants. Ceux-ci permettent de spécifier l'espace de noms
cible du schéma et de préciser quelques comportements par défaut du
schéma.
targetNamespace
La valeur de cet attribut est l'URI qui identifie l'espace de noms cible, c'est-a-dire l'espace de noms des éléments et types définis par le schéma. Si cet attribut est absent, les élements et types définis n'ont pas d'espace de noms.
elementFormDefault
et
attributeFormDefault
Ces deux attributs donnent la valeur par défaut de l'attribut
form
pour respectivement les éléments et les attributs. Les valeurs
possibles sont qualified
et unqualified
. La valeur par défaut est
unqualified
.
blockDefault
et
finalDefault
Ces deux attributs donnent la valeur par défaut des attributs
block
et final
.
Les valeurs possibles pour blockDefault
sont
#all
ou une liste de valeurs parmi les valeurs
extension
, restriction
et
substitution
. Les valeurs possibles pour
finalDefault
sont #all
ou une
liste de valeurs parmi les valeurs extension
,
restriction
, list
et
union
.
Dans l'exemple suivant, le schéma déclare que l'espace de noms
cible est identifié par l'URI
http://www.omega-one.org/~carton
et que tous les
éléments doivent être qualifiés dans les documents valides. L'espace de
noms par défaut est déclaré égal à l'espace de noms cible afin de
simplifier l'écriture du schéma.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema targetNamespace="http://www.omega-one.org/~carton" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.omega-one.org/~carton"> ...
Il est possible dans un document de donner explicitement le schéma
devant servir à le valider. On utilise un des attributs
schemaLocation
ou
noNamespaceSchemaLocation
dans l'élément racine du
document à valider. Ces deux attributs se trouvent dans l'espace de
noms des instances de schémas identifié par l'URI
http://www.w3.org/2001/XMLSchema-instance
.
L'attribut schemaLocation
est utilisé lors de
l'utilisation d'espaces de noms alors que l'attribut
noNamespaceSchemaLocation
est utilisé lorsque le
document n'utilise pas d'espace de noms
La valeur de l'attribut schemaLocation
est une
suite d'URI séparés par des espaces. Ces URI vont par paires et le
nombre d'URI doit donc être pair. Le premier URI de chaque paire
identifie un espace de noms et le second donne l'adresse du schéma à
utiliser pour les éléments et attributs dans cet espace de noms.
L'espace de noms identifié par le premier URI doit donc être l'espace
de noms cible du schéma donné par le second. La valeur de l'attribut
schemaLocation
prend donc la forme générale
suivante
schemaLocation="namespace1 schema1 namespace2 ... namespaceN schemaN"
où namespacei
est l'espace de noms cible du
schéma schemai
.
Le logiciel qui effectue la validation se base sur la valeur de
l'attribut schemaLocation
pour chercher la définition
de chaque élément ou attribut dans le schéma correspondant à son espace
de noms.
La valeur de l'attribut
noNamespaceSchemaLocation
est simplement l'URL d'un
unique schéma qui doit permettre de valider l'intégralité du document.
Il n'est, en effet, pas possible de distinguer les éléments qui n'ont
pas d'espace de noms.
Dans l'exemple suivant, le document déclare que le schéma se
trouve dans le fichier local bibliography.xsd
et
que l'espace de noms cible de ce schéma est identifié par l'URI
http://www.omega-one.org/~carton/
.
<?xml version="1.0" encoding="iso-8859-1"?> <bibliography xsi:schemaLocation="http://www.omega-one.org/~carton/ bibliography.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> ...
L'élément xsd:annotation
permet d'ajouter des
commentaires dans un schéma. Il peut être enfant de l'élément xsd:schema
pour des commentaires globaux. Il
peut également être enfant des éléments xsd:element
, xsd:attribute
pour ajouter des commentaires aux
déclarations d'éléments et d'atttributs ainsi que de xsd:simpleType
et xsd:complexType
pour ajouter des commentaires aux
définitions de type. Contrairement aux commentaires XML, ces commentaires
font partie à part entière du schéma XML et constituent sa
documentation.
<xsd:annotation> <xsd:documentation xml:lang="fr"> Commentaire en français </xsd:documentation> <xsd:appInfo> Information destinée aux applications </xsd:appInfo> </xsd:annotation>
Pour qu'un document soit valide pour un schéma, tout élément apparaissant dans le document doit être déclaré dans le schéma. Cette déclaration lui donne un type qui détermine, d'une part, les contenus possibles et, d'autre part, les attributs autorisés et obligatoires. Contrairement aux DTD, les attributs ne sont pas directement associés aux éléments. Ils font partie des types qui sont donnés aux éléments.
Le type donné à un élément peut être soit un type nommé soit un type anonyme. Dans le premier cas, le type est soit un type prédéfini dont le nom fait partie de l'espace de noms des schémas soit un type défini globalement dans le schéma. Dans le second cas, le type est défini explicitement à la déclaration de l'élément.
La déclaration la plus simple d'un élément prend la forme suivante.
<xsd:element name="element
" type="type
"/>
où element
et
type
sont respectivement le nom et le type de
l'élément. Ce type peut être un des types prédéfinis comme
xsd:string
ou xsd:integer
ou
encore un type défini dans le schéma. L'exemple suivant déclare
l'élément title
de type
xsd:string
. Le nom du type doit être un nom qualifié
comme ici par le préfixe xsd
associé à l'espace de
noms des schémas. Cette règle s'applique aussi lorsque le type est
défini dans le schéma.
<xsd:element name="title" type="xsd:string"/> <xsd:element name="title" type="tns:Title"/>
Lorsque le type est simple, il est possible de donner une valeur
par défaut ou une valeur fixe à l'élément comme dans les deux exemples
suivants. Il faut pour cela donner des valeurs aux attributs default
ou fixed
de l'élément xsd:element
.
<xsd:element name="title" type="xsd:string" default="Titre par défaut"/>
<xsd:element name="title" type="xsd:string" fixed="Titre fixe"/>
Lors de la déclaration d'un élément, il est possible de décrire
explicitement le type. La déclaration du type est alors le contenu de
l'élément xsd:element
. Le type est
alors local et sa déclaration prend alors une des deux formes suivantes
où element
est le nom de l'élément
déclaré.
<xsd:element name="element
">
<xsd:simpleType>
...
</xsd:simpleType>
</xsd:element>
<xsd:element name="element
">
<xsd:complexType>
...
</xsd:complexType>
</xsd:element>
Un élément global, c'est-à-dire dont la déclaration par
xsd:element
est enfant direct de l'élément
xsd:schema
, peut être utilisé par des définitions de
type. Ces définitions de type se contentent de faire référence à
l'élément global de la façon suivante. Ce mécanisme permet une certaine
modularité dans l'écriture des schémas puisqu'il évite des
répétitions.
<!-- Déclaration globale de l'élément title --> <xsd:element name="title" type="Title"/> ... <!-- Définition d'un type global ou local --> <xsd:complexType ... > ... <!-- Utilisation de l'élément title --> <xsd:element ref="title"/> ... </xsd:complexType>
Les deux attributs name
et
ref
ne peuvent pas être présents
simultanément dans l'élément xsd:element
. Par
contre, l'un des deux doit toujours être présent soit pour donner le nom
de l'élément défini soit pour référencer un élément déjà défini.
Deux éléments définis non globalement dans un schéma peuvent avoir
le même nom tout en ayant des types différents. Il s'agit en fait
d'éléments différents mais ayant le même nom. Cette possibilité est
absente des DTD où tous les éléments sont globaux et ne peuvent avoir
qu'un seul type. Le schéma suivant définit deux éléments de même nom
local
mais de types xsd:string
et
xsd:integer
. Le premier élément apparaît uniquement
dans le contenu de l'élément strings
alors que le
second apparaît uniquement dans le contenu de l'élément
integers
. C'est donc le contexte qui permet de
distinguer les deux éléments de nom local
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> ... <xsd:element name="strings"> <xsd:complexType> <xsd:sequence> <!-- Déclaration du premier élément local --> <xsd:element name="local" type="xsd:string" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="integers"> <xsd:complexType> <xsd:sequence> <!-- Déclaration du second élément local --> <xsd:element name="local" type="xsd:integer" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
Un document valide pour le schéma précédent est le suivant.
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?> <lists> <strings> <local>Une chaîne</local> <local>A string</local> </strings> <integers> <local>-1</local> <local>1</local> </integers> </lists>
D'autres exemples de schémas déclarant plusieurs éléments de même nom mais de types différents sont donnés pour les restrictions de types complexes à contenu complexe.
Parmi les types, les schémas XML distinguent les types
simples introduits par le constructeur xsd:simpleType
et les types
complexes introduits par le constructeur xsd:complexType
. Les types simples décrivent des
contenus textuels, c'est-à-dire ne contenant que du texte. Ils peuvent
être utilisés pour les éléments comme pour les attributs. Ils sont
généralement obtenus par dérivation des types prédéfinis. Au contraire,
les types complexes décrivent des contenus purs constitués uniquement
d'éléments ou des contenus mixtes constitués de texte et d'éléments. Ils
peuvent uniquement être utilisés pour déclarer des éléments. Seuls les
types complexes peuvent définir des attributs.
Les schémas permettent de définir une hiérarchie de types qui sont obtenus par extension ou restriction de types déjà définis. L'extension de type est similaire à l'héritage des langages de programmation orientés objet comme Java ou C++. Elle permet de définir un nouveau type en ajoutant des éléments et/ou des attributs à un type. La restriction permet au contraire d'imposer des contraintes supplémentaires au contenu et aux attributs.
Tous les types prédéfinis ou définis dans un schéma sont dérivés du
type xsd:anyType
. Ce type est aussi le type par
défaut lorsqu'une déclaration d'élément ne spécifie pas le type comme la
déclaration suivante.
<!-- Le type de l'élément object est xsd:anyType --> <xsd:element name="object"/>
Les schémas possèdent de nombreux types prédéfinis. Certains,
comme xsd:int
et xsd:float
,
proviennent des langages de programmation, certains, comme
xsd:date
et xsd:time
, sont
inspirés de normes ISO (ISO 8601 dans ce cas) et d'autres encore, comme
xsd:ID
, sont hérités des DTD. Ces types autorisent
l'écriture de schémas concis et très précis. Beaucoup d'entre eux
pourraient être redéfinis par restriction de types de base
mais leur présence comme types de base simplifie le travail.
Beaucoup de types numériques sont prédéfinis pour les nombres
entiers et flottants. Certains types comme xsd:int
ou xsd:double
correspondent à un codage précis et
donc à une précision fixée alors que d'autres types comme
xsd:integer
ou xsd:decimal
autorisent une précision arbitraire. Ces derniers types sont
à privilégier sauf quand le schéma décrit des données avec un
codage bien déterminé.
xsd:boolean
Valeur booléenne avec true
ou
1
pour vrai et
false
ou 0
pour
faux
xsd:byte
Nombre entier signé sur 8 bits
xsd:unsignedByte
Nombre entier non signé sur 8 bits
xsd:short
Nombre entier signé sur 16 bits
xsd:unsignedShort
Nombre entier non signé sur 16 bits
xsd:int
Nombre entier signé sur 32 bits
xsd:unsignedInt
Nombre entier non signé sur 32 bits
xsd:long
Nombre entier signé sur 64 bits. Ce type dérive du type
xsd:integer
.
xsd:unsignedLong
Nombre entier non signé sur 64 bits
xsd:integer
Nombre entier sans limite de précision. Ce type n'est pas
primitif et dérive du type xsd:decimal
.
xsd:positiveInteger
Nombre entier strictement positif sans limite de précision
xsd:negativeInteger
Nombre entier strictement négatif sans limite de précision
xsd:nonPositiveInteger
Nombre entier négatif ou nul sans limite de précision
xsd:nonNegativeInteger
Nombre entier positif ou nul sans limite de précision
xsd:float
Nombre flottant sur 32 bits conforme à la norme IEEE 754
xsd:double
Nombre flottant sur 64 bits conforme à la norme IEEE 754
xsd:decimal
Nombre décimal sans limite de précision
Les schémas possèdent bien sûr un type pour les chaînes de caractères ainsi que quelques types pour les noms qualifiés et non qualifiés.
xsd:string
Chaîne de caractères composée de caractères Unicode
xsd:normalizedString
Chaîne de caractères normalisée, c'est-à-dire ne contenant pas
de tabulation U+09
, de saut de ligne
U+0A
ou de retour chariot U+0D
.
xsd:token
Chaîne de caractères normalisée (comme ci-dessus) et ne contenant pas en outre des espaces en début ou en fin ou des espaces consécutifs
xsd:Name
xsd:QName
xsd:NCName
Nom non qualifié,
c'est-à-dire sans caractère ':'
xsd:language
Code de langue sur deux lettres de la norme ISO 639 comme
fr
ou en
éventuellement suivi
d'un code de pays de la norme ISO 3166 comme
en-GB
. C'est le type de
l'attribut particulier xml:lang
auquel il est spécialement destiné.
xsd:anyURI
Un URI comme http://www.omega-one.org/~carton/
.
C'est le type de l'attribut particulier xml:base
.
xsd:base64Binary
Données binaires représentées par une chaîne au format Base 64.
xsd:hexBinary
Données binaires représentées par une chaîne au format Hex.
Les deux types xsd:normalizedString
et
xsd:token
méritent quelques explications. D'une
part, il faut bien distinguer le type xsd:token
du
type xsd:NMTOKEN
. Le type
xsd:token
accepte des valeurs contenant
éventuellement des espaces alors que le type
xsd:NMTOKEN
accepte uniquement un jeton qui ne contient jamais
d'espace. D'autre part, les deux types
xsd:normalizedString
et xsd:token
ne restreignent pas les valeurs possibles pour un document valide mais
modifient le traitement des caractères d'espacement à
l'analyse lexicale. Le type xsd:normalizedString
n'interdit pas de mettre des caractères d'espacement autres que des
espaces. En revanche, tous les caractères d'espacement sont convertis
en espaces par l'analyseur lexical. De la même façon, le type
xsd:token
n'interdit pas de mettre des caractères
d'espacement en début ou en fin ou des caractères d'espacement
consécutifs. En revanche, les caractères d'espacement en début ou en
fin sont supprimés et les suites de caractères d'espacement sont
remplacées par un seul espace par l'analyseur lexical.
Quelques types des schémas imposent des formats standards pour écrire les dates et les heures. Ils s'appuient sur la norme ISO 8601. Leur grand intérêt est d'imposer une écriture normalisée pour les dates et les heures et d'en faciliter ainsi le traitement.
xsd:time
Heure au format hh:mm:ss[.sss][TZ]
, par
exemple 14:07:23
. La partie fractionnaire
.sss
des secondes est optionnelle. Tous les autres
champs sont obligatoires. Les nombres d'heures, minutes et de
secondes doivent être écrits avec deux chiffres en complétant avec
0
. L'heure peut être suivie d'un décalage horaire
TZ
qui est soit Z
pour le temps
universel soit un décalage commençant par +
ou
-
comme -07:00
.
xsd:date
Date au format YYYY-MM-DD
, par exemple
2008-01-16
. Tous les champs sont
obligatoires.
xsd:dateTime
Date et heure au format YYYY-MM-DDThh:mm:ss
comme 2008-01-16T14:07:23
. Tous les champs sont
obligatoires.
xsd:duration
Durée au format PnYnMnDTnHnMnS
comme
P1Y6M
, P1M12DT2H
et
P1YD3H10S
.
xsd:dayTimeDuration
Durée au format PnDTnHnMnS
comme
P7DT4H3M2S
.
xsd:yearMonthDuration
Durée au format PnYnM
comme
P1Y6M
.
xsd:gYear
Année du calendrier grégorien au format
YYYY
comme 2011
.
xsd:gYearMonth
Année et mois du calendrier grégorien au format
YYYY-MM
comme 1966-06
pour
juin 1966.
xsd:gMonth
Mois du calendrier grégorien au format MM
comme 01
pour janvier.
xsd:gMonthDay
Jour et mois du calendrier grégorien au format
MM-DD
comme 12-25
pour le jour
de Noël.
xsd:gDay
Jour (dans le mois) du calendrier grégorien au format
DD
comme 01
pour le premier
de chaque mois.
Les schémas XML reprennent certains types des DTD pour les attributs. Ces types facilitent la traduction automatique des DTD en schémas. Pour des raisons de compatibilité, ces types sont réservés aux attributs.
xsd:ID
nom XML identifiant un élément
xsd:IDREF
référence à un élément par son identifiant
xsd:IDREFS
liste de références à des éléments par leurs identifiants
xsd:NMTOKEN
xsd:NMTOKENS
liste de jetons séparés par des espaces
xsd:ENTITY
entité externe non XML
xsd:ENTITIES
liste d'entités externes non XML séparées par des espaces
xsd:NOTATION
notation
Les types simples définissent uniquement des contenus textuels.
Ils peuvent être utilisé pour les éléments ou les attributs. Ils sont
introduits par l'élément xsd:simpleType
. Un type
simple est souvent obtenu par restriction d'un autre type défini. Il
peut aussi être construit par union d'autres types simples ou par
l'opérateur de listes. La déclaration d'un type simple a la forme
suivante.
<xsd:simpleType ...> ... </xsd:simpleType>
L'élément xsd:simpleType
peut avoir un attribut
name
si la déclaration est globale. La
déclaration du type se fait ensuite dans le contenu de l'élément
xsd:simpleType
comme dans l'exemple suivant.
<xsd:simpleType name="Byte"> <xsd:restriction base="xsd:nonNegativeInteger"> <xsd:maxInclusive value="255"/> </xsd:restriction> </xsd:simpleType>
Les types complexes définissent des contenus purs (constitués
uniquement d'éléments), des contenus textuels ou des contenus mixtes.
Tous ces contenus peuvent comprendre des attributs. Les types complexes
peuvent seulement être utilisés pour les éléments. Ils sont introduits
par l'élément xsd:complexType
. Un type complexe peut
être construit explicitement ou être dérivé d'un autre type par extension ou restriction.
La construction explicite d'un type se fait en utilisant les
opérateurs de séquence xsd:sequence
, de choix
xsd:choice
ou d'ensemble xsd:all
.
La construction du type se fait directement dans le contenu de l'élément
xsd:complexType
et prend donc la forme
suivante.
<!-- Type explicite --> <xsd:complexType ...> <!-- Construction du type avec xsd:sequence, xsd:choice ou xsd:all --> ... </xsd:complexType>
Si le type est obtenu par extension ou restriction d'un autre
type, l'élément xsd:complexType
doit contenir un
élément xsd:simpleContent
ou
xsd:complexContent
qui précise si le contenu est
purement textuel ou non. La déclaration d'un type complexe prend alors
une des deux formes suivantes.
<!-- Type dérivé à contenu textuel --> <xsd:complexType ...> <xsd:simpleContent> <!-- Extension ou restriction --> ... </xsd:simpleContent> </xsd:complexType>
<!-- Type dérivé à contenu pur ou mixte --> <xsd:complexType ...> <xsd:complexContent> <!-- Extension ou restriction --> ... </xsd:complexContent> </xsd:complexType>
Le contenu d'un élément est pur lorsqu'il ne
contient que des éléments qui, eux-mêmes, peuvent à leur tour contenir
du texte et/ou des éléments. Il est, au contraire,
mixte lorsqu'il contient du texte autre que des
caractères d'espacement en dehors de ses enfants. La construction de
types pour les contenus mixtes est très facile et très souple avec les
schémas. L'attribut mixed
de l'élément
xsd:complexType
permet de construire un
type avec du contenu mixte. Il faut, pour cela, lui donner la valeur
true
.
Le contenu d'un élément est valide pour un type déclaré mixte si
le contenu devient valide pour le type non mixte correspondant lorsque
tout le texte en dehors des enfants est supprimé. Dans l'exemple
suivant, l'élément person
doit contenir, un élément
firstname
et un élément lastname
dans cet ordre. Puisque son type est déclaré mixte, il peut en outre
contenir du texte comme ci-dessous.
<xsd:element name="person">
<xsd:complexType mixed="true">
<xsd:sequence>
<xsd:element name="firstname" type="xsd:string"/>
<xsd:element name="lastname" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
Le document suivant est valide pour le schéma précédent. En
revanche, il ne le serait pas sans la valeur true
donnée à l'attribut mixed
dans le schéma. Le contenu
de l'élément person
est valide car si on retire le
texte en dehors de ses enfants firstname
et
lastname
(texte en gras ci-dessous), on obtient un
contenu valide pour le type sans mixed="true"
. Il
serait, par exemple, impossible de changer l'ordre des enfants
firstname
et lastname
car ce type
spécifie qu'ils doivent apparaître dans cet ordre.
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?> <person> Prénom : <firstname>Albert</firstname>, Nom : <lastname>Einstein</lastname>. </person>
Le schéma précédent n'a pas d'équivalent dans les DTD. Dès que le contenu d'un élément est déclaré mixte dans une DTD, il n'y a plus aucun contrôle sur l'ordre et le nombre d'occurrences de ses enfants. Le schéma suivant donne un exemple de contenu mixte équivalent à un contenu mixte d'une DTD.
<xsd:element name="book">
<xsd:complexType mixed="true">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="em"/>
<xsd:element ref="cite"/>
</xsd:choice>
</xsd:complexType>
</xsd:element>
L'exemple précédent est équivalent au fragment suivant de DTD.
<!ELEMENT book (#PCDATA | em | cite)* >
Les constructeurs de types permettent de définir des nouveaux types en combinant des types déjà définis. Ils sont en fait assez semblables aux différents opérateurs des DTD.
Si un type complexe déclare uniquement des attributs, le contenu
de l'élément doit être vide. Par exemple, le type suivant déclare un type
Link
. Tout élément de ce type doit avoir un contenu
vide et un attribut ref
de type
xsd:IDREF
. Il s'agit en fait d'une extension du type vide par
ajout d'attributs.
<xsd:element name="link" type="Link"/> <xsd:complexType name="Link"> <xsd:attribute name="ref" type="xsd:IDREF" use="required"/> </xsd:complexType>
Le fragment de document suivant est valide pour le schéma précédent.
<link ref="id-42"/>
L'opérateur xsd:sequence
définit un nouveau
type formé d'une suite des éléments énumérés. C'est l'équivalent de
l'opérateur ','
des DTD. Les éléments énumérés
peuvent être soit des éléments explicites, soit des éléments référencés
avec l'attribut ref
soit des types construits
récursivement avec les autres opérateurs. Dans l'exemple suivant, un
élément book
doit contenir les éléments
title
, author
,
year
et publisher
dans cet
ordre.
<xsd:element name="book"> <xsd:complexType> <xsd:sequence> <xsd:element name="title" type="xsd:string"/> <xsd:element name="author" type="xsd:string"/> <xsd:element name="year" type="xsd:string"/> <xsd:element name="publisher" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element>
Cette déclaration est équivalente à la déclaration suivante dans une DTD.
<!ELEMENT book (title, author, year, publisher)>
Le fragment de document ci-dessous est valide pour la déclaration
de l'élément book
.
<book> <title>XML langage et applications</title> <author>Alain Michard</author> <year>2001</year> <publisher>Eyrolles</publisher> </book>
Un autre exemple de type construit avec l'opérateur
xsd:sequence
est donné comme exemple de type mixte. Le nombre d'occurences
de chaque élément dans la séquence est 1 par défaut mais il peut être
modifié par les attributs minOccurs
et maxOccurs
.
L'opérateur xsd:choice
définit un nouveau type
formé d'un des éléments énumérés. C'est l'équivalent de l'opérateur
'|'
des DTD. Dans l'exemple suivant, le
contenu de l'élément publication
doit être un des
éléments book
, article
ou
report
. Ces trois éléments sont référencés et
doivent donc être définis globalement dans le schéma.
<xsd:element name="publication"> <xsd:complexType> <xsd:choice> <xsd:element ref="book"/> <xsd:element ref="article"/> <xsd:element ref="report"/> </xsd:choice> </xsd:complexType> </xsd:element>
Cette déclaration est équivalente à la déclaration suivante dans une DTD.
<!ELEMENT publication (book | article | report)>
Un autre exemple de type construit avec l'opérateur
xsd:choice
est donné comme exemple de type mixte. Il est bien sûr possible
d'imbriquer les opérateurs xsd:sequence
et
xsd:choice
. Dans l'exemple suivant, l'élément
book
contient soit un seul élément
author
soit un élément authors
contenant au moins deux éléments author
. Cette
dernière contrainte est imposée par la valeur 2
de
l'attribut minOccurs
.
<xsd:element name="book" minOccurs="1" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <xsd:element name="title" type="xsd:string"/> <xsd:choice> <xsd:element name="author" type="xsd:string"/> <xsd:element name="authors"> <xsd:complexType> <xsd:sequence> <xsd:element name="author" type="xsd:string" minOccurs="2" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:choice> <xsd:element name="year" type="xsd:string"/> ... </xsd:sequence>
Le document suivant est valide pour le schéma précédent.
<?xml version="1.0" encoding="iso-8859-1"?> <bibliography> <!-- Livre à un seul auteur --> <book key="Michard01" lang="fr"> <title>XML langage et applications</title> <author>Alain Michard</author> <year>2001</year> <publisher>Eyrolles</publisher> </book> <!-- Livre à deux auteurs --> <book key="ChagnonNolot07" lang="fr"> <title>XML</title> <authors> <author>Gilles Chagnon</author> <author>Florent Nolot</author> </authors> <year>2007</year> <publisher>Pearson</publisher> </book> </bibliography>
L'opérateur xsd:all
n'a pas d'équivalent dans
les DTD. Il définit un nouveau type dont chacun des éléments doit
apparaître une fois dans un ordre quelconque. Dans la déclaration
ci-dessous, les éléments contenus dans l'élément book
peuvent apparaître dans n'importe quel ordre.
<xsd:element name="book"> <xsd:complexType> <xsd:all> <xsd:element name="title" type="xsd:string"/> <xsd:element name="author" type="xsd:string"/> <xsd:element name="year" type="xsd:string"/> <xsd:element name="publisher" type="xsd:string"/> </xsd:all> </xsd:complexType> </xsd:element>
Le document suivant est un document valide où l'élément
book
a la déclaration précédente. L'ordre des
enfants de l'élément book
peut être variable.
<?xml version="1.0" encoding="iso-8859-1"?> <bibliography> <book key="Michard01" lang="fr"> <author>Alain Michard</author> <title>XML langage et applications</title> <publisher>Eyrolles</publisher> <year>2001</year> </book> <book key="Zeldman03" lang="en"> <title>Designing with web standards</title> <author>Jeffrey Zeldman</author> <year>2003</year> <publisher>New Riders</publisher> </book> ... </bibliography>
L'utilisation de l'élément xsd:all
doit
respecter quelques contraintes qui limitent fortement son intérêt. Un
opérateur xsd:all
ne peut pas être imbriqué avec
d'autres constructeurs xsd:sequence
,
xsd:choice
ou même xsd:all
. D'une
part, les seuls enfants possibles de xsd:all
sont des
éléments xsd:element
. D'autre part, l'élément
xsd:all
est toujours enfant de
xsd:complexType
ou
xsd:complexContent
.
Les attributs minOccurs
et
maxOccurs
des éléments apparaissant sous
l'opérateur xsd:all
ne peuvent pas avoir des valeurs
quelconques. La valeur de l'attribut minOccurs
doit
être 0
ou 1
et la valeur de
l'attribut maxOccurs
doit être 1
qui est la valeur par défaut. Les attributs
minOccurs
et maxOccurs
peuvent
aussi apparaître comme attribut de xsd:all
. Dans ce
cas, leurs valeurs s'appliquent à tous les éléments
xsd:element
enfants de xsd:all
.
Les valeurs autorisées pour minOccurs
sont
0
et 1
et la seule valeur
autorisée pour maxOccurs
est
1
.
Dans la déclaration suivante de l'élément book
,
ses enfants peuvent apparaître dans n'importe quel ordre et chacun d'eux
peut avoir 0 ou 1 occurrence.
<xsd:element name="book"> <xsd:complexType> <xsd:all minOccurs="0"> <xsd:element name="title" type="xsd:string"/> <xsd:element name="author" type="xsd:string"/> <xsd:element name="year" type="xsd:string"/> <xsd:element name="publisher" type="xsd:string"/> </xsd:all> </xsd:complexType> </xsd:element>
L'opérateur xsd:union
définit un nouveau type
simple dont les valeurs sont celles des types listés dans l'attribut
memberTypes
.
Le type IntegerOrUnbounded
défini ci-dessous
pourrait être le type de l'attribut maxOccurs
tel qu'il pourrait apparaître dans un
schéma pour les schémas. Les valeurs de ce type sont soit un entier
positif ou nul du type xsd:nonNegativeInteger
soit
l'unique chaîne unbounded
du type
Unbounded
. Ce dernier type est obtenu par
restriction du type xsd:string
.
<xsd:attribute name="maxOccurs" type="IntegerOrUnbounded"/>
<xsd:simpleType name="IntegerOrUnbounded">
<xsd:union memberTypes="xsd:nonNegativeInteger Unbounded"/>
</xsd:simpleType>
<xsd:simpleType name="Unbounded">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="unbounded"/>
</xsd:restriction>
</xsd:simpleType>
Les types paramètres de l'opérateur d'union peuvent aussi être
anonymes. Ils sont alors explicités directement dans le contenu de
l'élément xsd:union
comme dans l'exemple suivant qui
conduit à une définition équivalence à celle de l'exemple
précédent.
<xsd:simpleType name="IntegerOrUnbounded"> <xsd:union memberTypes="xsd:nonNegativeInteger"> <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:enumeration value="unbounded"/> </xsd:restriction> </xsd:simpleType> </xsd:union> </xsd:simpleType>
L'opérateur xsd:list
définit un nouveau type
simple dont les valeurs sont les listes de valeurs du type simple donné
par l'attribut itemType
. Il ne s'agit
pas de listes générales comme dans certains langages de
programmation. Il s'agit uniquement de listes de valeurs séparées par
des espaces. Ces listes sont souvent utilisées comme valeurs
d'attributs. Les valeurs du type simple donné par
itemType
ne peuvent pas comporter de caractères d'espacement
qui perturberaient la séparation entre les valeurs. L'exemple suivant
définit des types pour les listes d'entiers et pour les listes de 5
entiers.
<!-- Type pour les listes d'entiers -->
<xsd:simpleType name="IntList">
<xsd:list itemType="xsd:integer"/>
</xsd:simpleType>
<!-- Type pour les listes de 5 entiers -->
<xsd:simpleType name="IntList5">
<xsd:restriction base="IntList">
<xsd:length value="5"/>
</xsd:restriction>
</xsd:simpleType>
Les attributs minOccurs
et
maxOccurs
permettent de préciser le
nombre minimal ou maximal d'occurrences d'un élément ou d'un groupe.
Ils sont l'équivalent des opérateurs ?
,
*
et +
des DTD. Ils peuvent
apparaître comme attribut des éléments xsd:element
,
xsd:sequence
, xsd:choice
et
xsd:all
. L'attribut minOccurs
prend un entier comme valeur. L'attribut maxOccurs
prend un entier ou la chaîne unbounded
comme valeur
pour indiquer qu'il n'y a pas de nombre maximal. La valeur par défaut
de ces deux attributs est la valeur 1
.
L'utilisation des attributs minOccurs
et
maxOccurs
est illustrée par l'équivalent en schéma de
quelques fragments de DTD
<!ELEMENT elem (elem1, elem2?, elem3*)>
<xsd:element name="elem"> <xsd:complexType> <xsd:sequence> <xsd:element ref="elem1"/> <xsd:element ref="elem2" minOccurs="0"/> <xsd:element ref="elem3" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element>
<!ELEMENT elem (elem1, (elem2 | elem3)?, elem4)>
<xsd:element name="elem">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="elem1"/>
<xsd:choice minOccurs="0">
<xsd:element ref="elem2"/>
<xsd:element ref="elem3"/>
</xsd:choice>
<xsd:element ref="elem4"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<!ELEMENT elem (elem1, elem2, elem3)*>
<xsd:element name="elem"> <xsd:complexType> <xsd:sequence minOccurs="0" maxOccurs="unbounded"> <xsd:element ref="elem1"/> <xsd:element ref="elem2"/> <xsd:element ref="elem3"/> </xsd:sequence> </xsd:complexType> </xsd:element>
<!ELEMENT elem (elem1 | elem2 | elem3)*>
<xsd:element name="elem"> <xsd:complexType> <xsd:choice minOccurs="0" maxOccurs="unbounded"> <xsd:element ref="elem1"/> <xsd:element ref="elem2"/> <xsd:element ref="elem3"/> </xsd:choice> </xsd:complexType> </xsd:element>
<!ELEMENT elem (elem1, elem2, elem3)+>
<xsd:element name="elem"> <xsd:complexType> <xsd:sequence minOccurs="1" maxOccurs="unbounded"> <xsd:element ref="elem1"/> <xsd:element ref="elem2"/> <xsd:element ref="elem3"/> </xsd:sequence> </xsd:complexType> </xsd:element>
L'opérateur xsd:any
permet d'introduire dans un
document un ou des éléments externes au schéma, c'est-à-dire non définis
dans le schéma. Le nombre d'éléments externes autorisés peut-être
spécifié avec les attributs minOccurs
et maxOccurs
.
La validation de ces éléments externes est contrôlée par l'attribut
processContents
qui peut prendre les valeurs
strict
, lax
et
skip
. La valeur par défaut est
strict
. Lorsque la valeur est
strict
, les éléments externes doivent être validés
par un autre schéma déterminé par l'espace de noms de ces éléments pour
que le document global soit valide. Lorsque la valeur est
skip
, les éléments externes ne sont pas validés. La
valeur lax
est intermédiaire entre
strict
et skip
. La validation des
éléments externes est tentée mais elle peut échouer.
Le schéma suivant autorise zéro ou un élément externe dans le
contenu de l'élément person
après l'élément
lastname
.
<?xml version="1.0" encoding="iso-8859-1"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="person">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="firstname" type="xsd:string"/>
<xsd:element name="lastname" type="xsd:string"/>
<xsd:any processContents="lax" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Le document suivant est valide pour le schéma précédent.
<?xml version="1.0" encoding="utf-8"?>
<person>
<firstname>Elizabeth II Alexandra Mary</firstname>
<lastname>Windsor</lastname>
<title>Queen of England</title>
</person>
L'attribut namespace
de l'élément
xsd:any
permet de préciser les espaces de noms
auxquels doivent appartenir les éléments externes. Sa valeur doit être
une suite d'URI identifiant des espaces de noms séparés par des espaces.
Les valeurs particulières ##any
,
##other
, ##local
et
##targetNamepspace
peuvent aussi apparaître dans la
liste des espaces de noms. La valeur par défaut ##any
n'impose aucune restriction sur l'espace de noms des éléments externes.
Les valeurs ##targetNamepspace
et
##other
autorisent respectivement des éléments dont
l'espace de noms est égal ou différent de l'espace de noms cible du
schéma. La valeur ##local
autorise des éléments
ayant des noms non qualifiés et n'appartenant donc à aucun espace de
noms.
Dans le schéma suivant, l'élément externe ajouté dans le contenu
de l'élément person
doit appartenir à l'espace de
noms XHTML.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="person"> <xsd:complexType> <xsd:sequence> <xsd:element name="firstname" type="xsd:string"/> <xsd:element name="lastname" type="xsd:string"/> <xsd:any processContents="lax" namespace="http://www.w3.org/1999/xhtml" minOccurs="0"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
Le document suivant est valide pour le schéma précédent.
<?xml version="1.0" encoding="utf-8"?> <person> <firstname>Victor</firstname> <lastname>Hugo</lastname> <html:ul xmlns:html="http://www.w3.org/1999/xhtml"> <html:li>Romancier</html:li> <html:li>Poète</html:li> <html:li>Dramaturge</html:li> </html:ul> </person>
Il existe également un élément xsd:anyAttribute
pour autoriser des attributs externes au schéma.
Cette section aborde deux aspects techniques de la validation du contenu d'éléments purs. Ces deux aspects sont la présence des caractères d'espacement et le déterminisme des contenus. Ils ont déjà été abordés pour les DTD.
Lorsque le contenu d'un élément d'un élément pur est validé, les caractères d'espacement qui se trouvent hors de ses enfants sont ignorés. Ceci autorise l'indentation des documents XML sans perturber la validation.
Le contenu des éléments purs et mixtes doit être déterministe.
Ceci signifie que la présence d'une balise ouvrante dans le contenu doit
complètement déterminer d'où provient celle-ci dans la définition du
type. Cette restriction est identique à celle portant sur les
expressions définissant le contenu d'un élément pur dans une DTD. Le
schéma suivant n'est pas valable car le contenu de l'élément
item
n'est pas déterministe. Une balise ouvrante
<item1>
peut provenir de la première ou de la
seconde déclaration d'élément item1
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="item"> <xsd:complexType> <xsd:choice> <xsd:sequence> <xsd:element name="item1" type="xsd:string"/> <xsd:element name="item2" type="xsd:string"/> </xsd:sequence> <xsd:sequence> <xsd:element name="item1" type="xsd:string"/> <xsd:element name="item3" type="xsd:string"/> </xsd:sequence> </xsd:choice> </xsd:complexType> </xsd:element> </xsd:schema>
La déclaration d'un attribut est semblable à la déclaration d'un
élément mais elle utilise l'élément xsd:attribute
au
lieu de l'élément xsd:element
. Les attributs name
et type
de
xsd:attribute
spécifient respectivement le nom et le
type de l'attribut. Le type d'un attribut est nécessairement un type
simple puisque les attributs ne peuvent contenir que du texte. La
déclaration d'un attribut prend la forme suivante.
<xsd:attribute name="name
" type="type
"/>
L'exemple suivant déclare un attribut format
de
type xsd:string
.
<xsd:attribute name="format" type="xsd:string"/>
Comme pour un élément, le type d'un attribut peut être anonyme. Il
est alors défini dans le contenu de l'élément
xsd:attribute
. Cette possibilité est illustrée par
l'exemple suivant. La valeur de l'attribut lang
déclaré ci-dessous peut être la chaîne en
ou la chaîne
fr
.
<xsd:attribute name="lang"> <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:enumeration value="en"/> <xsd:enumeration value="fr"/> </xsd:restriction> </xsd:simpleType> </xsd:attribute>
Les déclarations d'attributs se placent normalement dans les définitions de types complexes qui peuvent être globaux ou locaux. Les types simples ne peuvent pas avoir d'attributs. La définition d'un type complexe se compose de la description du contenu suivie de la déclaration des attributs. L'ordre de déclarations des attributs est sans importance puisque l'ordre des attributs dans une balise n'est pas fixe.
Dans l'exemple suivant, le type complexe List
déclare deux attributs form
et
lang
. Les déclarations de ces deux attributs se
situent après la description du contenu du type List
constitué d'une suite d'éléments item
. Le type de
l'attribut form
est le type prédéfini
xsd:string
alors que le type de l'attribut
lang
est le type global et simple
Lang
défini dans la suite du schéma.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:complexType name="List"> <!-- Contenu du type List --> <xsd:sequence maxOccurs="unbounded"> <xsd:element name="item" type="xsd:string"/> </xsd:sequence> <!-- Déclaration des attributs locaux form et lang du type List --> <xsd:attribute name="form" type="xsd:string"/> <xsd:attribute name="lang" type="Lang"/> </xsd:complexType> <!-- Type global et simple Lang pour l'attribut lang --> <xsd:simpleType name="Lang"> <xsd:restriction base="xsd:string"> <xsd:length value="2"/> </xsd:restriction> </xsd:simpleType> <xsd:element name="list" type="List"/> </xsd:schema>
Le fragment de document suivant est valide pour le schéma précédent.
<list form="long" lang="en"> <item>Item 1</item> <item>Item 2</item> </list>
Un attribut peut aussi être global lorsque sa déclaration par
xsd:attribute
est enfant direct de l'élément xsd:schema
. Cet attribut peut alors être ajouté
à différents types complexes. La définition du type utilise l'élément
xsd:attribute
avec un attribut ref
qui remplace les deux attributs
name
et type
. Cet attribut
ref
contient le nom de l'attribut global à ajouter.
La déclaration globale d'un attribut est justifiée lorsque celui-ci a
des occurrences multiples. Elle accroît la modularité des schémas en
évitant de répéter la même déclaration dans plusieurs types.
Le schéma suivant déclare un attribut global lang
de type xsd:language
. Cet attribut est ajouté à deux
reprises dans le type global Texts
et dans le type
anonyme de l'élément text
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- Déclaration de l'attribut global lang --> <xsd:attribute name="lang" type="xsd:language"/> <xsd:element name="texts" type="Texts"/> <xsd:complexType name="Texts"> <xsd:sequence> <xsd:element name="text" maxOccurs="unbounded"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:string"> <!-- Ajout de l'attribut lang au type anonyme --> <xsd:attribute ref="lang"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element> </xsd:sequence> <!-- Ajout de l'attribut lang au type Texts --> <xsd:attribute ref="lang"/> </xsd:complexType> </xsd:schema>
Lorsqu'un schéma déclare un espace de noms cible, les
attributs globaux appartiennent automatiquement à cet espace de noms.
Ceci signifie d'abord qu'ils doivent être référencés par leur nom
qualifié dans le schéma. L'ajout d'un attribut de nom
name
à un type complexe prend alors la forme suivante
où le préfixe tns
est associé à l'espace de noms
cible du schéma.
<xsd:attribute ref="tns:name"/>
Cela signifie aussi qu'ils doivent avoir un nom qualifié dans les documents instance comme dans l'exemple suivant.
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?> <tns:texts tns:lang="fr" xmlns:tns="http://www.omega-one.org/~carton/"> <text>Texte en français</text> <text tns:lang="en">Text in english</text> </tns:texts>
Par défaut, un attribut est optionnel. Il peut être présent ou
absent. Il peut aussi être rendu obligatoire ou
interdit en donnant la valeur required
ou prohibited
à l'attribut use
de l'élément
xsd:attribute
. L'attribut use
peut aussi prendre la valeur optional
. Cette valeur est très peu utilisée car
c'est la valeur par défaut. La valeur prohibited
est
utile dans les restrictions de types pour modifier l'utilisation d'un
attribut.
Les valeurs optional
et
required
de l'attribut use
sont
donc équivalentes à #IMPLIED
et #REQUIRED
utilisés dans les déclarations
d'attributs des DTD. Dans
l'exemple suivant, les attributs lang
,
xml:id
et dummy
sont respecivement
optionnel, obligatoire et interdit.
<xsd:attribute name="lang" type="xsd:NMTOKEN" use="optional"/> <xsd:attribute name="xml:id" type="xsd:ID" use="required"/> <xsd:attribute name="dummy" type="xsd:string" use="prohibited"/>
Le schéma suivant donne une utilisation réaliste de la valeur
prohibited
pour l'attribut use
. Le type Date
déclare un
attribut format
optionnel. Le type
Date-8601
est une restriction du type
Date
. L'attribut format
devient
interdit et ne peut plus apparaître.
<?xml version="1.0" encoding="iso-8859-1"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="Date">
<xsd:simpleContent>
<xsd:extension base="xsd:date">
<!-- Attribut format optionnel dans le type Date -->
<xsd:attribute name="format" type="xsd:string"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:complexType name="Date-8601">
<xsd:simpleContent>
<xsd:restriction base="Date">
<!-- Attribut format interdit dans le type Date-8601 -->
<xsd:attribute name="format" type="xsd:string" use="prohibited"/>
</xsd:restriction>
</xsd:simpleContent>
</xsd:complexType>
<xsd:element name="date" type="Date-8601"/>
</xsd:schema>
<?xml version="1.0" encoding="iso-8859-1"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="Date">
<xsd:simpleContent>
<xsd:extension base="xsd:date">
<!-- Attribut format optionnel dans le type Date -->
<xsd:attribute name="format" type="xsd:string"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:complexType name="Date-8601">
<xsd:simpleContent>
<xsd:restriction base="Date">
<!-- Attribut format interdit dans le type Date-8601 -->
<xsd:attribute name="format" type="xsd:string" use="prohibited"/>
</xsd:restriction>
</xsd:simpleContent>
</xsd:complexType>
<xsd:element name="date" type="Date-8601"/>
</xsd:schema>
Le fragment de document suivant est valide pour ce schéma.
L'attribut format
ne peut pas être présent dans
l'élément date
.
<date format="iso-8601"/></date>
Comme pour les éléments, il est possible de donner une valeur par
défaut ou une valeur fixe à un attribut. La valeur de l'attribut
default
ou de l'attribut fixed
de l'élément
xsd:attribute
permet de spécifier cette valeur. Il
va de soi qu'une valeur par défaut n'est autorisée que si l'attribut est
optionnel. Il est également interdit de donner simultanément une valeur
par défaut et une valeur fixe. L'attribut fixed
est
équivalent à #FIXED
utilisé dans les
déclarations d'attribut des DTD. Dans le premier exemple suivant, la
valeur par défaut de l'attribut lang
est
fr
et dans le second exemple, sa valeur est fixée à
la valeur en
.
<xsd:attribute name="lang" type="xsd:NMTOKEN" default="fr"/>
<xsd:attribute name="lang" type="xsd:NMTOKEN" fixed="en"/>
De même qu'il existe un élément xsd:any
pour
autoriser des éléments externes, il existe aussi un élément
xsd:anyAttribute
pour autoriser des attributs
externes au schéma. Il possède également les attributs
processContents
et namespace
pour
contrôler la validation et l'espace de noms des attributs externes
ajoutés dans les documents.
Dans le schéma suivant, l'élément person
peut
avoir des attributs appartenant à l'espace de noms identifié par
l'URI http://www.omega-one.org/~carton/
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="person"> <xsd:complexType> <xsd:sequence> <xsd:element name="firstname" type="xsd:string"/> <xsd:element name="lastname" type="xsd:string"/> </xsd:sequence> <xsd:anyAttribute processContents="lax" namespace="http://www.omega-one.org/~carton/"/> </xsd:complexType> </xsd:element> </xsd:schema>
Le document suivant est valide pour le schéma précédent.
<?xml version="1.0" encoding="utf-8"?>
<person tns:id="id42" xmlns:tns="http://www.omega-one.org/~carton/">
<firstname>Victor</firstname>
<lastname>Hugo</lastname>
</person>
L'extension est la première façon d'obtenir un type dérivé à partir d'un type de base. L'idée générale de l'extension est de rajouter du contenu et des attributs. Elle s'apparente à la dérivation de types des langages de programmation orientés objet comme Java ou C++. Les contenus du type dérivé ne sont généralement pas valides pour le type de base car des éléments et/ou des attributs nouveaux peuvent apparaître. L'extension s'applique aux types simples et aux types complexes mais elle donne toujours un type complexe.
L'extension d'un type est introduite par l'élément xsd:extension
dont l'attribut base
donne le nom du type de base. Celui-ci peut
être un type prédéfini ou un type défini dans le schéma. Le contenu de
l'élément xsd:extension
explicite le contenu et les
attributs à ajouter au type de base. L'élément
xsd:extension
est enfant d'un élément xsd:simpleContent
ou xsd:complexContent
, lui-même enfant de l'élément
xsd:complexType
.
L'extension d'un type simple ne permet pas de changer le contenu
mais permet uniquement d'ajouter des attributs pour donner un type
complexe à contenu simple. C'est en fait la seule façon d'obtenir un
tel type s'il on exclut l'extension ou la restriction d'un type qui est
déjà dans cette catégorie. Lors d'une extension d'un type simple,
l'élément xsd:extension
est toujours
enfant d'un élément xsd:simpleContent
.
Les déclarations des attributs qui sont ajoutés sont placées dans le
contenu de l'élément xsd:extension
.
Le fragment de schéma suivant définit un type
Price
qui étend le type prédéfini
xsd:decimal
en lui ajoutant un attribut
currency
de type xsd:string
<xsd:complexType name="Price"> <xsd:simpleContent> <xsd:extension base="xsd:decimal"> <!-- Attribut ajouté --> <xsd:attribute name="currency" type="xsd:string"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> <xsd:element name="price" type="Price"/>
Le fragment de document suivant est valide pour le schéma précédent.
<price currency="euro">3.14</price>
Il est possible d'étendre un type complexe à contenu simple pour
lui ajouter de nouveaux attributs. On obtient alors un nouveau type
complexe à contenu simple qui possède les attributs du type de base et
ceux déclarés par l'extension. L'extension d'un tel type est similaire
à l'extension d'un type simple. L'élément xsd:extension
est encore enfant d'un élément
xsd:simpleContent
. Les déclarations des
attributs qui sont ajoutés sont placées dans le contenu de l'élément
xsd:extension
.
Dans le schéma suivant, le type Price
est
étendu en un type LocalType
qui possède un nouvel
attribut country
de type
xsd:string
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- Type de base complexe à contenu simple --> <xsd:complexType name="Price"> <xsd:simpleContent> <xsd:extension base="xsd:decimal"> <!-- Attribut ajouté au type xsd:decimal --> <xsd:attribute name="currency" type="xsd:string"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> <!-- Extension du type de base --> <xsd:complexType name="LocalPrice"> <xsd:simpleContent> <xsd:extension base="Price"> <!-- Attribut ajouté au type Price --> <xsd:attribute name="country" type="xsd:string"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> <xsd:element name="price" type="LocalPrice"/> </xsd:schema>
Le fragment de document suivant est valide pour le schéma
précédent. Comme l'ordre des attributs est sans importance, l'attribut
country
aurait pu être placé avant l'attribut
currency
.
<price currency="euro" country="France">3.14</price>
L'extension d'un type complexe à contenu complexe consiste à ajouter du contenu et/ou des attributs. Le contenu est ajouté après le contenu du type de base. L'ajout d'attribut est semblable au cas des types complexes à contenu simple.
Dans le schéma suivant le type Fullname
étend
le type Name
en lui ajoutant un élément
title
et un attribut id
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- Type de base --> <xsd:complexType name="Name"> <xsd:sequence> <xsd:element name="firstname" type="xsd:string"/> <xsd:element name="lastname" type="xsd:string"/> </xsd:sequence> </xsd:complexType> <!-- Extension du type de base --> <xsd:complexType name="Fullname"> <xsd:complexContent> <xsd:extension base="Name"> <xsd:sequence> <!-- Ajout de l'élément title après firstname et lastname --> <xsd:element name="title" type="xsd:string"/> </xsd:sequence> <!-- Ajout de l'attribut id --> <xsd:attribute name="id" type="xsd:ID"/> </xsd:extension> </xsd:complexContent> </xsd:complexType> ... </xsd:schema>
L'élément title
est ajouté après le contenu
du type Name
qui est constitué des deux éléments
firstname
et lastname
. Le
document suivant est valide pour le schéma précédent.
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?> <names> <fullname id="id40"> <firstname>Alexander III Alexandrovich</firstname> <lastname>Romanov</lastname> <title>Tsar of Russia</title> </fullname> <fullname id="id52"> <firstname>Elizabeth II Alexandra Mary</firstname> <lastname>Windsor</lastname> <title>Queen of England</title> </fullname> </names>
La restriction est la deuxième façon d'obtenir un type dérivé à partir d'un type de base. L'idée générale de la restriction est de définir un nouveau type dont les contenus au sens large sont des contenus du type de base. Par contenus au sens large, on entend les contenus proprement dits ainsi que les valeurs des attributs. La restriction s'applique aux types simples et aux types complexes mais elle prend des formes différentes suivant les cas.
La restriction d'un type est introduite par l'élément xsd:restriction
dont l'attribut base
donne le nom du type de base. Celui-ci peut
être un type prédéfini ou un type défini dans le schéma. Le contenu de
l'élément xsd:restriction
explicite les restrictions
au type de base. Dans le cas d'un type simple, l'élément
xsd:restriction
est enfant direct de l'élément
xsd:simpleType
. Dans le cas d'un type
complexe, il est enfant d'un élément xsd:simpleContent
ou xsd:complexContent
, lui-même enfant de l'élément
xsd:complexType
.
Les schémas définissent un certain nombre de types de base. Tous les autres types simples sont obtenus par restriction directe ou multiple de ces différents types de base. La restriction des types simples est effectuée par l'intermédiaire de facettes qui imposent des contraintes aux contenus. Toutes les facettes ne s'appliquent pas à tous les types simples. On donne d'abord quelques exemples de restrictions classiques à l'aide des principales facettes puis une liste exhaustive des facettes.
Il est possible de restreindre les contenus en donnant une valeur
minimale et/ou une valeur maximale avec les éléments
xsd:minInclusive
,
xsd:minExclusive
,
xsd:maxInclusive
et
xsd:maxExclusive
. Ces contraintes s'appliquent aux
types numériques pour lesquels elles ont un sens. Dans l'exemple
suivant, le type donné à l'élément year
est un
entier entre 1970 et 2050 inclus. Le type utilisé dans cet exemple est
un type anonyme.
<xsd:element name="year"> <xsd:simpleType> <xsd:restriction base="xsd:integer"> <xsd:minInclusive value="1970"/> <xsd:maxInclusive value="2050"/> </xsd:restriction> </xsd:simpleType> </xsd:element>
Un exemple de contenu valide pour l'élément
year
est donné ci-dessous.
<year>1966</year>
La restriction par intervalle peut aussi s'appliquer aux dates et aux heures comme le montre l'exemple suivant.
<xsd:attribute name="date">
<xsd:simpleType>
<xsd:restriction base="xsd:date">
<!-- Date après le 31 décembre 2001 exclus -->
<xsd:minExclusive value="2001-12-31"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
Un exemple de valeur valide pour l'attribut
date
est donné ci-dessous.
<event date="2006-06-24">...</event>
Il est possible de donner explicitement une liste des valeurs
possibles d'un type prédéfini ou déjà défini avec l'élément
xsd:enumeration
. Dans l'exemple suivant, le type
donné à l'élément language
comprend uniquement les
trois chaînes de caractères de
,
en
et fr
. Le type utilisé est un
type nommé Language
.
<xsd:element name="language" type="Language"/> <xsd:simpleType name="Language"> <xsd:restriction base="xsd:language"> <xsd:enumeration value="de"/> <xsd:enumeration value="en"/> <xsd:enumeration value="fr"/> </xsd:restriction> </xsd:simpleType>
Un exemple de valeur valide pour l'attribut
date
est donné ci-dessous.
<language>en</language>
Il est possible de restreindre les valeurs en donnant, avec
l'élément xsd:pattern
, une expression rationnelle qui décrit
les valeurs possibles d'un type prédéfini ou déjà défini. Le contenu
est valide s'il est conforme à l'expression rationnelle. Dans
l'exemple suivant, le type ISBN
décrit explicitement
toutes les formes possibles des numéros ISBN à 10 chiffres.
<xsd:simpleType name="ISBN"> <xsd:restriction base="xsd:string"> <xsd:pattern value="\d-\d{2}-\d{6}-[\dX]"/> <xsd:pattern value="\d-\d{3}-\d{5}-[\dX]"/> <xsd:pattern value="\d-\d{4}-\d{4}-[\dX]"/> <xsd:pattern value="\d-\d{5}-\d{3}-[\dX]"/> </xsd:restriction> </xsd:simpleType>
Un élement isbn
déclaré du type
ISBN
défini ci-dessus pourrait avoir
le contenu suivant qui correspond au second motif utilisé
ci-dessus.
<isbn>2-311-01400-6</isbn>
Le type suivant Identifier
définit un type
pour les noms XML. Il aurait
aussi pu être décrit avec l'expression rationnelle
\i\c*
.
<xsd:simpleType name="Identifier">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[:_A-Za-z][-.:_0-9A-Za-z]*"/>
</xsd:restriction>
</xsd:simpleType>
Un élement identifier
déclaré du type
Identifier
défini ci-dessus pourrait avoir
le contenu suivant.
<identifier>tns:id-42</identifier>
Pour que le contenu soit valide, il faut que celui-ci, pris dans
son intégralité, soit conforme à l'expression rationnelle. Il ne
suffit pas qu'un fragment (une sous-chaîne) de celui-ci soit conforme.
Le contenu abc123xyz
n'est, par exemple, pas
conforme à l'expression \d{3}
bien que le fragment
123
le soit. Les ancres '^'
et
'$'
sont
implicitement ajoutées à l'expression. Pour avoir une expression qui
accepte éventuellement un fragment du contenu, il suffit d'ajouter
.*
au début et à la fin de celle-ci. Le contenu
abc123xyz
est, par exemple, conforme à l'expression
.*\d{3}.*
.
Il faut remarquer que les restrictions par énumération ou par
motif se combinent avec un ou logique. Le contenu
doit être une des valeurs énumérées ou il doit être conforme à un des
motifs. Au contraire, les autres restrictions comme
minInclusive
et maxInclusive
se
combinent avec un et logique. Le contenu doit
vérifier toutes les contraintes pour être valide.
La liste suivante décrit toutes les facettes. Pour chacune d'entre elles sont donnés les types sur lesquels elle peut s'appliquer.
xsd:enumeration
Cette facette permet d'énumérer explicitement les valeurs
autorisées. Elle s'applique à tous les types simples y compris les
types construits avec xsd:union
et xsd:list
.
xsd:pattern
Cette facette permet de donner une expression rationnelle pour
contraindre les valeurs. Elle ne s'applique pas uniquement aux
types dérivés de xsd:string
mais à tous les types
simples y compris les types numériques et les types contruits avec
xsd:union
et xsd:list
.
L'utilisation avec xsd:decimal
permet de
restreindre, par exemple, aux nombres ayant 4 chiffres pour la
partie entière et 2 pour la partie fractionnaire. Lorsque cette
facette est appliquée à un type construit avec
xsd:list
, la contrainte porte sur les items de la
liste et non sur la liste elle-même.
xsd:length
,
xsd:minLength
et
xsd:maxLength
Ces trois facettes donnent respectivement une longueur fixe ou
des longueurs minimale et maximale. Elles s'appliquent aux types
dérivés de xsd:string
ainsi qu'aux types
construits avec l'opérateur xsd:list
.
xsd:minInclusive
,
xsd:minExclusive
,
xsd:maxInclusive
et
xsd:maxExclusive
Ces quatre facettes donnent des valeurs minimale et maximale en incluant ou non la borne donnée. Ces facettes s'appliquent à tous les types numériques ainsi qu'à tous les types de date et d'heure.
xsd:fractionDigits
et
xsd:totalDigits
Ces deux facettes fixent respectivement le nombre maximal de
chiffres de la partie fractionnaire (à droite de la virgule) et le
nombre maximal de chiffres en tout. Il s'agit de valeurs maximales.
Il n'est pas possible de spécifier des valeurs minimales. De même,
il n'est pas possible de spécifier le nombre maximal de chiffres de
la partie entière (à gauche de la virgule). Ces deux facettes
s'appliquent uniquement aux types numériques dérivés de xsd:decimal
. Ceci inclut tous les types
entiers mais exclut les types xsd:float
et xsd:double
.
xsd:whiteSpace
Cette facette est particulière. Elle ne restreint pas les
valeurs valides mais elle modifie le traitement des caractères
d'espacement à l'analyse lexicale. Cette facette peut
prendre les trois valeurs preserve
,
replace
et collapse
qui
correspondent à trois modes de fonctionnement de l'analyseur
lexical.
preserve
Dans ce mode, les caractères d'espacement sont laissés inchangés par l'analyseur lexical.
replace
Dans ce mode, chaque caractère d'espacement est remplacé
par un espace U+20
. Le résultat est donc du
type prédéfini xsd:normalizedString
.
collapse
Dans ce mode, le traitement du mode précédent
replace
est d'abord appliqué puis les espaces
en début et en fin sont supprimés et les suites d'espaces
consécutifs sont remplacées par un seul espace. Le résultat est
donc du type prédéfini xsd:token
Cette facette ne s'applique qu'aux types dérivés de xsd:string
. Une dérivation ne peut que
renforcer le traitement des caractères d'espacement en passant d'un
mode à un mode plus strict (preserve
→
replace
→ collapse
). Les
changements dans l'autre sens sont impossibles.
Les types complexes à contenu simple sont toujours obtenus par extension d'un type simple en lui ajoutant des attributs. La restriction d'un de ces types peut porter sur le type simple du contenu ou/et sur les attributs. Il est possible de remplacer le type du contenu par un type obtenu par restriction. Il est aussi possible de changer le type d'un attribut ou de modifier son utilisation. Un attribut optionnel peut, par exemple, devenir obligatoire. La restriction d'un type complexe à contenu simple donne toujours un type complexe à contenu simple.
Par défaut, le nouveau type complexe défini est identique au type
de base. Pour modifier le type du contenu, l'élément xsd:restriction
contient un élément xsd:simpleType
qui donne explicitement le nouveau
type du contenu. Ce type doit être obtenu par restriction du type qui
définit le contenu du type de base.
Dans le schéma suivant, un type Base
est défini
par extension du type simple xsd:string
en lui
ajoutant un attribut format
. Le type
Derived
est ensuite obtenu en restreignant le type du
contenu aux chaînes d'au plus 32 caractères.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- Type de base --> <xsd:complexType name="Base"> <xsd:simpleContent> <xsd:extension base="xsd:string"> <xsd:attribute name="format" type="xsd:string"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> <!-- Restriction du type de base --> <xsd:complexType name="Derived"> <xsd:simpleContent> <xsd:restriction base="Base"> <!-- Nouveau type pour le contenu du type Derived --> <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:maxLength value="32"/> </xsd:restriction> </xsd:simpleType> </xsd:restriction> </xsd:simpleContent> </xsd:complexType> <xsd:element name="base" type="Base"/> <xsd:element name="derived" type="Derived"/> </xsd:schema>
Dans le fragment de document ci-dessous, les deux éléments
base
et derived
ont des contenus
valides pour le schéma précédent.
<base format="string">Une chaîne très longue de plus de 32 caractères</base> <derived format="string">Une de moins de 32 caractères</derived>
La restriction peut aussi changer les types des attributs et leur
utilisation. Les attributs dont certaines propriétés changent sont
redéclarés dans le nouveau type. Les autres restent implicitement
inchangés. Le type d'un attribut peut être remplacé par un type obtenu
par restriction. Ce type peut, bien sûr, être nommé ou anonyme.
L'utilisation des attributs peut aussi être restreinte. Un attribut
optionnel peut devenir interdit avec use="prohibited"
ou obligatoire avec use="required"
. L'inverse est en
revanche interdit. Il est également impossible d'ajouter de nouveaux
attributs. Si un attribut possède une valeur par défaut ou une valeur
fixe, celle-ci ne peut être ni modifiée ni supprimée.
Dans le schéma suivant, le type de base Base
possède plusieurs attributs dont le type dérivé Derived
modifie l'utilisation.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- Type de base --> <xsd:complexType name="Base"> <xsd:simpleContent> <xsd:extension base="xsd:string"> <xsd:attribute name="decimal" type="xsd:decimal"/> <xsd:attribute name="string" type="xsd:string"/> <xsd:attribute name="optional" type="xsd:string"/> <xsd:attribute name="required" type="xsd:string" use="required"/> <xsd:attribute name="fixed" type="xsd:string" fixed="Fixed"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> <!-- Restriction du type de base --> <xsd:complexType name="Derived"> <xsd:simpleContent> <xsd:restriction base="Base"> <!-- Restriction du type de l'attribut --> <xsd:attribute name="decimal" type="xsd:integer"/> <!-- Le nouveau type doit être dérivé du type initial --> <xsd:attribute name="decimal" type="xsd:string"/> <!-- Restriction du type de l'attribut avec un type anonyme --> <xsd:attribute name="string"> <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:maxLength value="32"/> </xsd:restriction> </xsd:simpleType> </xsd:attribute> <!-- Restriction de l'utilisation de l'attribut --> <xsd:attribute name="optional" type="xsd:string" use="required"/> <!-- Impossible d'étendre l'utilisation de l'attribut --> <xsd:attribute name="required" type="xsd:string"/> <!-- Impossible de changer ou supprimer la valeur fixe --> <xsd:attribute name="fixed" type="xsd:string"/> <!-- Impossible d'ajouter un nouvel attribut --> <xsd:attribute name="newattr" type="xsd:string"/> </xsd:restriction> </xsd:simpleContent> </xsd:complexType> ... </xsd:schema>
Il est encore possible de changer simultanément le type du contenu
et certaines propriétés des attributs. Dans le schéma suivant, le type
est restreint au chaînes d'au plus 32 caractères et le type
xsd:decimal
de l'attribut decimal
est remplacé par le type xsd:integer
qui est bien un
type dérivé de xsd:decimal
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- Type de base --> <xsd:complexType name="Base"> <xsd:simpleContent> <xsd:extension base="xsd:string"> <xsd:attribute name="decimal" type="xsd:decimal"/> <xsd:attribute name="unchanged" type="xsd:string"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> <!-- Restriction du type de base --> <xsd:complexType name="Derived"> <xsd:simpleContent> <xsd:restriction base="Base"> <xsd:simpleType> <!-- Nouveau type pour le contenu du type Derived --> <xsd:restriction base="xsd:string"> <xsd:maxLength value="32"/> </xsd:restriction> </xsd:simpleType> <!-- Restriction du type de l'attribut --> <xsd:attribute name="decimal" type="xsd:integer"/> <!-- Attribut unchanged inchangé --> </xsd:restriction> </xsd:simpleContent> </xsd:complexType> <xsd:element name="base" type="Base"/> <xsd:element name="derived" type="Derived"/> </xsd:schema>
Dans le fragment de document ci-dessous, les deux éléments
base
et derived
ont des contenus
valides pour le schéma précédent.
<base decimal="3.14">Une chaîne très longue de plus de 32 caractères</base> <derived decimal="3">Une de moins de 32 caractères</derived>
La restriction d'un type complexe permet d'imposer des contraintes
aussi bien au contenu qu'aux attributs. La restriction doit rester
fidèle au principe que tous les contenus possibles du type restreint
doivent être valides pour le type de base. Il est, par exemple,
possible de changer le type d'un élément en un type restreint ou de
changer le nombre d'occurrences d'un éléments ou d'un bloc avec les
attributs minOccurs
et maxOccurs
.
Les restrictions portant sur les attributs sont identiques à celles
possibles pour un type complexe à contenu simple.
Le nouveau type est défini en écrivant sa définition comme s'il
s'agissait d'une première définition. Dans le schéma suivant, le type
Shortname
est obtenu par restriction du type
Name
. La valeur de l'attribut
maxOccurs
pour l'élément firstname
passe de unbounded
à 1
.
L'attribut id
devient obligatoire.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="names"> <xsd:complexType> <xsd:choice maxOccurs="unbounded"> <xsd:element name="name" type="Name"/> <xsd:element name="shortname" type="Shortname"/> </xsd:choice> </xsd:complexType> </xsd:element> <!-- Type de base --> <xsd:complexType name="Name"> <xsd:sequence> <!-- Nombre illimité d'occurrences de l'élément firstname --> <xsd:element name="firstname" type="xsd:string" maxOccurs="unbounded"/> <xsd:element name="lastname" type="xsd:string"/> </xsd:sequence> <xsd:attribute name="id" type="xsd:ID"/> </xsd:complexType> <!-- Restriction du type Name --> <xsd:complexType name="Shortname"> <xsd:complexContent> <xsd:restriction base="Name"> <xsd:sequence> <!-- Nombre limité d'occurrences de l'élément firstname --> <xsd:element name="firstname" type="xsd:string" maxOccurs="1"/> <xsd:element name="lastname" type="xsd:string"/> </xsd:sequence> <!-- Attribut id obligatoire --> <xsd:attribute name="id" type="xsd:ID" use="required"/> </xsd:restriction> </xsd:complexContent> </xsd:complexType> </xsd:schema>
Le document suivant est valide pour le schéma précédent.
<?xml version="1.0" encoding="iso-8859-1"?> <names xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <name> <firstname>Elizabeth II</firstname> <firstname>Alexandra</firstname> <firstname>Mary</firstname> <lastname>Windsor</lastname> </name> <shortname id="id-42"> <firstname>Bessiewallis</firstname> <lastname>Warfield</lastname> </shortname> </names>
Il est aussi possible de restreindre un type complexe en
remplaçant le type d'un élément par un type dérivé. Dans l'exemple
suivant, le type de l'élément integer
est
xsd:integer
dans le type Base
. Ce
type est remplacé par le type xsd:nonNegativeInteger
dans le type Restriction
. Le schéma suivant déclare
deux éléments locaux de même nom integer
mais de
types différents.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:complexType name="Base"> <xsd:sequence> <xsd:element name="integer" type="xsd:integer"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="Restriction"> <xsd:complexContent> <xsd:restriction base="Base"> <xsd:sequence> <xsd:element name="integer" type="xsd:nonNegativeInteger"/> </xsd:sequence> </xsd:restriction> </xsd:complexContent> </xsd:complexType> ... </xsd:schema>
Une restriction d'un type complexe à contenu complexe peut aussi
supprimer un des choix possibles dans un élément
xsd:choice
. Dans l'exemple suivant, le choix
integer
a été supprimé dans le type
Float
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- Type de base --> <xsd:complexType name="Number"> <xsd:choice> <xsd:element name="integer" type="xsd:integer"/> <xsd:element name="float" type="xsd:float"/> <xsd:element name="double" type="xsd:double"/> </xsd:choice> </xsd:complexType> <!-- Restriction du type de base --> <xsd:complexType name="Float"> <xsd:complexContent> <xsd:restriction base="Number"> <xsd:choice> <!-- Suppression de l'élément integer --> <xsd:element name="float" type="xsd:float"/> <xsd:element name="double" type="xsd:double"/> </xsd:choice> </xsd:restriction> </xsd:complexContent> </xsd:complexType> ... </xsd:schema>
Le document suivant est valide pour le schéma précédent. Il
utilise une substitution de
type avec l'attribut xsi:type
pour changer le
type de l'élément number
en
Float
.
<?xml version="1.0" encoding="iso-8859-1"?>
<numbers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<number>
<integer>42</integer>
</number>
<number xsi:type="Float">
<!-- Élément integer impossible -->
<integer>42</integer>
<float>3.14</float>
</number>
</numbers>
Les schémas XML prévoient plusieurs mécanismes de substitution au niveau des types et des éléments. Dans la substitution de type, un document peut changer explicitement le type associé à un élément afin d'y placer un contenu différent de celui prévu par le schéma. La substitution d'éléments va encore plus loin. Un document peut remplacer un élément par un autre élément.
Les substitutions ne sont pas toujours possibles. Une première condition pour qu'elles puissent s'effectuer est que les types soient compatibles. Il faut que le type de substitution soit un type dérivé du type initial. Les substitutions sont donc étroitement liées aux différentes façons d'obtenir des types dérivés par extension ou restriction.
Une seconde condition pour rendre possible les substitutions est que celles-ci doivent être autorisées par le schéma. Les schémas possèdent différents outils pour contrôler les substitutions.
L'annihilation est un mécanisme qui permet de mettre aucun contenu à un élément alors que le type de l'élément prévoit que le contenu est normalement non vide. Cette notion correspond à l'absence de valeur telle qu'elle existe dans les bases de données.
Le schéma doit d'abord autoriser le mécanisme en donnant la valeur
true
à l'attribut nillable
de
l'élément xsd:element
. La valeur par défaut de cet
attribut est false
. Le document doit ensuite,
explicitement, déclarer que l'élément n'a pas de valeur en donnant la
valeur true
à l'attribut xsi:nil
qui est dans l'espace de noms des
instances de schémas. Le contenu de l'élément doit alors être vide.
Dans le schéma suivant, l'élément item
est déclaré
annihilable.
<?xml version="1.0" encoding="iso-8859-1"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="list">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="item" nillable="true"
maxOccurs="unbounded" type="xsd:integer"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Le document suivant est valide pour ce schéma. L'élément
item
peut avoir un contenu vide si on lui ajoute un
attribut xsi:nil
avec la valeur
true
.
<?xml version="1.0" encoding="iso-8859-1"?> <list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <!-- Contenu normal --> <item>123</item> <!-- Contenu vide non autorisé --> <item></item> <!-- Contenu annihilé --> <item xsi:nil="true"></item> <!-- Contenu nécessairement vide : aucun espace --> <item xsi:nil="true"> </item> <item>789</item> </list>
Un type peut remplacer, dans une instance de document, un autre
type dont il dérive directement ou non. Soit, par exemple, un élément
elem
déclaré d'un type BaseType
.
Si un type ExtentedType
a été défini par extension ou
restriction du type BaseType
, il est possible, dans
une instance de document, de mettre un élément elem
avec un contenu de type ExtentedType
. Pour que le
document reste valide, l'élément elem
doit avoir un
attribut xsi:type
qui précise le type de son contenu.
Cet attribut est dans l'espace de
noms des instances de schémas. La substitution de type est
autorisée par défaut. Aucune déclaration n'est nécessaire dans le
schéma pour qu'elle puisse avoir lieu dans les documents. La
substitution de type peut, en revanche, être forcée ou bloquée par les
attributs abstract
et block
.
Dans l'exemple suivant, un type Name
est d'abord
déclaré puis un type Fullname
étend ce type en
ajoutant un élément title
et un attribut
id
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema targetNamespace="http://www.omega-one.org/~carton/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.omega-one.org/~carton/"> <xsd:element name="name" type="Name"/> ... <xsd:complexType name="Name"> <xsd:sequence> <xsd:element name="firstname" type="xsd:string"/> <xsd:element name="lastname" type="xsd:string"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="Fullname"> <xsd:complexContent> <xsd:extension base="Name"> <xsd:sequence> <xsd:element name="title" type="xsd:string"/> </xsd:sequence> <xsd:attribute name="id" type="xsd:ID"/> </xsd:extension> </xsd:complexContent> </xsd:complexType> </xsd:schema>
Le document suivant est valide pour ce schéma.
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?> <tns:names xmlns:tns="http://www.omega-one.org/~carton/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <!-- Élément name avec le type tns:Name --> <tns:name> <firstname>Bessiewallis</firstname> <lastname>Warfield</lastname> </tns:name> <!-- Élément name avec le type tns:Fullname --> <tns:name id="id52" xsi:type="tns:Fullname"> <firstname>Elizabeth II Alexandra Mary</firstname> <lastname>Windsor</lastname> <title>Queen of England</title> </tns:name> </tns:names>
L'attribut xsi:type
peut aussi changer le type
d'un élément en un autre type obtenu par restriction du type original.
Dans l'exemple suivant, un type Byte
est déclaré par
restriction du type prédéfini xsd:nonNegativeInteger
.
Cet type est équivalent au type xsd:byte
prédéfini dans les schémas.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema targetNamespace="http://www.omega-one.org/~carton/" xmlns="http://www.omega-one.org/~carton/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="value" type="xsd:integer"/> ... <xsd:simpleType name="Byte"> <xsd:restriction base="xsd:nonNegativeInteger"> <xsd:maxInclusive value="255"/> </xsd:restriction> </xsd:simpleType> </xsd:schema>
Le document suivant est valide pour ce schéma. Il est possible de
changer le type de l'élément value
en
xsd:nonNegativeInteger
car ce type prédéfini dérive du
type prédéfini xsd:integer
. Cet exemple illustre
aussi l'utilisation indispensable des espaces de noms. Il est, en effet,
nécessaire de déclarer trois espaces de noms : celui des éléments du
document, celui des schémas pour le type
xsd:nonNegativeInteger
et celui des instances de
schémas pour l'attribut xsi:type
.
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?> <tns:values xmlns:tns="http://www.omega-one.org/~carton/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <tns:value>-1</tns:value> <tns:value xsi:type="xsd:nonNegativeInteger">256</tns:value> <tns:value xsi:type="tns:Byte">255</tns:value> </tns:values>
Il est possible de spécifier qu'un élément peut être remplacé par
un autre élément dans les documents instance. Ce mécanisme est
différent de l'utilisation de l'attribut xsi:type
puisque c'est l'élément même qui est
remplacé et pas seulement le type. Le type de l'élément substitué doit
avoir un type dérivé du type de l'élément original.
La substitution d'élément se distingue en plusieurs points de la
substitution de type. Elle est évidemment beaucoup plus forte car elle
affecte les éléments qui peuvent apparaître dans les documents. Pour
cette raison, elle doit explicitement être prévue par le schéma par
l'intermédiaire de groupes de substitution qui décrivent quel élément
peut être remplacé et par quels éléments. En revanche, le document ne
signale pas la substitution comme il le fait pour une substitution de
type avec l'attribut xsi:type
.
Ce mécanisme est mis en œuvre en créant un groupe de
substitution. Un groupe est formé d'un élément
chef de groupe (group head en
anglais) et d'autres éléments qui se rattachent au chef de groupe. Le
chef de groupe peut être remplacé dans un document instance par
n'importe quel autre élément du groupe. Le chef de groupe n'est pas
identifié directement. En revanche, tous les autres éléments déclarent
leur rattachement au groupe avec l'attribut
substitutionGroup
dont la valeur est le nom du chef
de groupe. Les groupes de substitution peuvent être bloqués par
l'attribut final
.
Dans l'exemple suivant, le chef de groupe est l'élément
integer
. Les éléments positive
et
negative
peuvent être substitués à l'élément
integer
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- Chef de groupe --> <xsd:element name="integer" type="xsd:integer"/> <!-- Autres éléments du groupe --> <xsd:element name="positive" type="xsd:positiveInteger" substitutionGroup="integer"/> <xsd:element name="negative" type="xsd:negativeInteger" substitutionGroup="integer"/> <xsd:element name="integers"> <xsd:complexType> <xsd:sequence> <xsd:element ref="integer" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
Le document suivant est valide pour ce schéma. L'élément
integers
contient des éléments
positive
et negative
remplacent
des éléments integer
.
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?> <integers> <integer>0</integer> <!-- Élément positive se substituant à un élément integer --> <positive>1</positive> <!-- Élément negative se substituant à un élément integer --> <negative>-1</negative> <integer>-42</integer> </integers>
Depuis la version 1.1 des schémas, l'attribut
substitutionGroup
de xsd:element
peut contenir plusieurs noms d'éléments. Un élément peut ainsi
appartenir à plusieurs groupes de substitution alors que c'était
impossible avec la version 1.0.
Les substitutions peuvent être utilisées en cascade. Un élément
membre d'un groupe de substitution peut, lui-même, être chef d'un autre
groupe de substitution. Les membres de ce dernier groupe peuvent bien
sûr remplacer leur chef de groupe mais aussi son chef de groupe. Dans le
schéma suivant, l'élément head
est le chef d'un groupe
comprenant l'élément subs
. Cet élément
subs
est, à son tour, chef d'un groupe de substitution
comprenant l'élément subsubs
. Cet élément
subsubs
peut dont remplacer l'élément
subs
mais aussi l'élément
head
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- L'élément chef de groupe --> <xsd:element name="head" type="xsd:string"/> <!-- Un élément subs pouvant se substituer à head --> <xsd:element name="subs" type="xsd:string" substitutionGroup="head"/> <!-- Un élément subsubs pouvant se substituer à subs et à head --> <xsd:element name="subsubs" type="xsd:string" substitutionGroup="subs"/> <xsd:element name="heads"> <xsd:complexType> <xsd:sequence> <xsd:element ref="head" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
Le document suivant est valide pour le schéma précédent.
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
<heads>
<head>Élément head original</head>
<subs>Substitution de head par subs</subs>
<subsubs>Substitution de head par subsubs</subsubs>
<head>Autre élément head original</head>
</heads>
Les définitions circulaires de groupes de substitution sont interdites. Un chef de groupe ne peut pas être membre d'un groupe dont le chef serait lui même membre d'un de ses groupes. Les déclarations suivantes ne sont donc pas valides.
<xsd:element name="head" type="xsd:string" substitutionGroup="subs"/>
<xsd:element name="subs" type="xsd:string" substitutionGroup="head"/>
Les groupes de substitution permettent, quelquefois, de compenser
les lacunes de l'opérateur xsd:all
. Il est,
en effet, possible de simuler un opérateur xsd:choice
avec
un élément abstrait et un groupe de substitution.
Dans le schéma suivant, l'élément number
est
abstrait. Il doit nécessairement être remplacé, dans un document, par
un élément de son groupe de substitution, c'est-à-dire par un élément
integer
ou par un élément double
.
Il y a donc le choix entre un élément integer
ou un
élément double
. Le type de l'élément
number
est xsd:anyType
pour que
les types xsd:integer
et
xsd:double
des éléments integer
et
double
puissent en dériver.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="properties"> <xsd:complexType> <xsd:sequence> <xsd:element ref="property" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="property"> <xsd:complexType> <xsd:all> <xsd:element name="key" type="xsd:string"/> <xsd:element ref="number"/> <xsd:element name="condition" type="xsd:string" minOccurs="0"/> </xsd:all> </xsd:complexType> </xsd:element> <xsd:element name="number" type="xsd:anyType" abstract="true"/> <xsd:element name="integer" type="xsd:integer" substitutionGroup="number"/> <xsd:element name="double" type="xsd:double" substitutionGroup="number"/> </xsd:schema>
Il existe différents moyens de contrôler les substitutions de
types et d'éléments. Les types et éléments abstraits introduits par
l'attribut abstract
permettent de forcer une
substitution en empêchant un type ou un élément d'apparaître dans un
document. Les attributs block
et
final
permettent, au contraire, de limiter les
substitutions et les définitions de types dérivés.
Les trois attributs abstract
,
block
et final
s'appliquent aussi
bien aux declarations d'éléments qu'aux définitions de types. Il faut
prendre garde au fait que leurs significations dans ces deux cas sont
proches mais néanmoins différentes.
Le tableau suivant récapitule les utilisations des trois
attributs abstract
, block
et
final
pour les types et les éléments.
Attribut | Type | Élément |
---|---|---|
abstract | bloque l'utilisation du type dans les documents | bloque la présence de l'élément dans les documents |
block | bloque la substitution du type dans les documents | bloque la substitution de type pour cet élément dans les documents |
final | bloque la dérivation de types dans le schéma | bloque l'ajout d'éléments dans le groupe de substitution dans le schéma |
Les types simples sont obtenus par restrictions successives des
types prédéfinis en
utilisant des facettes.
Il est possible d'imposer, avec l'attribut fixed
, qu'une facette ne puisse plus être
modifiée dans une restriction supplémentaire.
L'attribut fixed
peut être utilisé dans toutes
les facettes xsd:minLength
, xsd:maxLength
, xsd:minInclusive
, …. Sa valeur par défaut
est la valeur false
. Lorsqu'il prend la valeur
true
, la valeur de la facette est bloquée et elle ne
peut plus être modifiée.
Dans le schéma suivant, le type ShortString
est obtenu par restriction du type xsd:string
. Il
impose une longueur maximale à la chaîne avec la facette
xsd:maxLength
. Cette facette est fixée avec
fixed="true"
. Le type
VeryShortString
est obtenu par restriction du type
ShortString
. Il ne peut pas donner une nouvelle
valeur à xsd:maxLength
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- Type de base : restriction du type xsd:string --> <xsd:simpleType name="ShortString"> <xsd:restriction base="xsd:string"> <!-- Facette fixée --> <xsd:maxLength value="32" fixed="true"/> </xsd:restriction> </xsd:simpleType> <!-- Restriction du type ShortString --> <xsd:simpleType name="VeryShortString"> <xsd:restriction base="ShortString"> <!-- Facette modifiée --> <xsd:minLength value="2"/> <!-- Facette impossible à modifier --> <xsd:maxLength value="16"/> </xsd:restriction> </xsd:simpleType> </xsd:schema> ...
Le document suivant est valide pour le schéma précédent.
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?> <strings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <string>Une chaîne assez courte</string> <string xsi:type="VeryShortString">Très courte</string> </strings>
Un type complexe peut être déclaré abstrait en donnant la valeur
true
à l'attribut abstract
de
l'élément xsd:complexType
. Un type
simple déclaré avec xsd:simpleType
ne peut pas être
abstrait.
Ce mécanisme est assez semblable à la notion de classe abstraite des langages de programmation orientés objet comme Java ou C++. Dans ces langages, un type déclaré abstrait peut être utilisé pour dériver d'autres types mais il ne peut pas être instancié. Ceci signifie qu'aucun objet de ce type ne peut être créé. Il est, en revanche, possible de créer des objets des types dérivés.
Lorsqu'un type est déclaré abstrait dans un schéma, celui-ci peut
encore être utilisé dans la déclaration d'un élément. En revanche,
l'élément ne pourra pas avoir ce type dans un document. Un document
valide doit nécessairement opérer une substitution de type par
l'intermédiaire de l'attribut xsi:type
ou une substitution d'élément
par l'intermédiaire d'un groupe
de substitution.
Dans l'exemple suivant, on définit un type abstrait
Price
et un type dérivé
InternPrice
. L'élément price
est
du type Price
. Il peut être substitué par
l'élément internprice
qui est de type
InternPrice
.
<?xml version="1.0" encoding="iso-8859-1"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- Type de base abstrait -->
<xsd:complexType name="Price" abstract="true">
<xsd:simpleContent>
<xsd:extension base="xsd:decimal">
<xsd:attribute name="currency" type="xsd:string"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<!-- Type dérivé concret -->
<xsd:complexType name="InternPrice">
<xsd:simpleContent>
<xsd:restriction base="Price">
<xsd:attribute name="currency" type="xsd:string" use="required"/>
</xsd:restriction>
</xsd:simpleContent>
</xsd:complexType>
<!-- Élément price de type abstrait -->
<xsd:element name="price" type="Price"/>
<!-- Élément interprice de type concret substituable à price -->
<xsd:element name="internprice" type="InternPrice" substitutionGroup="price"/>
<xsd:element name="prices">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="price" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Le document ci-dessous est valide pour le schéma donné ci-dessus.
L'élément price
n'apparaît pas avec le type
Price
qui est abstrait. Soit le type
Price
est remplacé par le type dérivé
InternPrice
, soit l'élément price
est remplacé par l'élément internprice
.
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?> <prices xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <!-- Élément de type Price non autorisé --> <price>78.9</price> <!-- Substitution de type --> <price xsi:type="InternPrice" currency="euro">12.34</price> <!-- Substitution d'élément --> <internprice currency="dollar">45.56</internprice> </prices>
Dans l'exemple suivant, on définit un type abstrait
AbstractType
sans contrainte. Ce type est alors
équivalent au type xsd:anyType
. On dérive ensuite
deux types par extension Derived1
et
Derived2
. Le premier type
Derived1
déclare un attribut att
de type xsd:string
et un élément
string
comme unique contenu. Le second type
Derived2
ne déclare aucun attribut mais il déclare
un contenu constitué d'un élément string
suivi d'un
élément integer
.
<?xml version="1.0" encoding="iso-8859-1"?>
<xsd:schema targetNamespace="http://www.omega-one.org/~carton/"
xmlns="http://www.omega-one.org/~carton/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="value" type="Abstract"/>
<xsd:element name="values">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="value" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="Abstract" abstract="true"/>
<xsd:complexType name="Derived1">
<xsd:complexContent>
<xsd:extension base="Abstract">
<xsd:sequence>
<xsd:element name="string" type="xsd:string"/>
</xsd:sequence>
<xsd:attribute name="att" type="xsd:string"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Derived2">
<xsd:complexContent>
<xsd:extension base="Abstract">
<xsd:sequence>
<xsd:element name="string" type="xsd:string"/>
<xsd:element name="integer" type="xsd:integer"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
Le document suivant est valide pour ce schéma. L'élément
value
apparaît deux fois dans le document mais avec
respectivement les types Derived1
et
Derived2
. Ces types sont déclarés à l'aide de
l'attribut xsi:type
.
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?> <tns:values xmlns:tns="http://www.omega-one.org/~carton/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <!-- Élément value de type Abstract impossible --> <tns:value xsi:type="tns:Derived1" att="avec un attribut"> <string>Une chaîne</string> </tns:value> <tns:value xsi:type="tns:Derived2"> <string>Un entier</string> <integer>-1</integer> </tns:value> </tns:values>
Un élément peut être déclaré abstrait en
donnant la valeur true
à l'attribut
abstract
de l'élément xsd:element
. Un élément déclaré abstrait peut
être utilisé dans la construction d'un type pour un autre élément. En
revanche, il ne peut pas apparaître dans un document instance.
L'élément doit nécessairement être remplacé par un autre élément.
Cette substitution est uniquement possible lorsque l'élément abstrait
est le chef d'un groupe de
substitution. Il peut alors être remplacé par n'importe quel
membre du groupe.
La contrainte imposée en rendant un élément abstrait est plus forte que celle imposée en rendant un type abstrait. Il n'est, en effet, plus possible de remplacer le type. Il faut nécessairement remplacer l'élément.
Dans le schéma suivant, l'élément value
est
déclaré abstrait. Il est le chef d'un groupe qui comprend uniquement
l'élément other
qui peut donc le remplacer.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- Un élément value abstrait --> <xsd:element name="value" type="xsd:string" abstract="true"/> <!-- Un élément other pouvant se substituer à value --> <xsd:element name="other" type="String27" substitutionGroup="value"/> <!-- Type obtenu par restriction de xsd:string --> <xsd:simpleType name="String27"> <xsd:restriction base="xsd:string"> <xsd:length value="27"/> </xsd:restriction> </xsd:simpleType> ...
Le document suivant est valide pour le schéma précédent.
L'élément abstrait value
n'apparaît pas. Il est
systématiquement remplacé par l'élément
other
.
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?> <values xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <!-- Élément value impossible --> <value>Une chaîne d'une autre longueur</value> <!-- Élément value impossible même avec une substitution de type --> <value xsi:type="String27">Une chaîne de 27 caractères</value> <!-- Substitution d'élément --> <other>Une chaîne de même longueur</other> </values>
Il est possible, dans un schéma de limiter dans les documents les
substitutions de types. L'attribut block
de
l'élément xsd:complexType
permet
d'empêcher qu'un élément du type défini puisse prendre un autre type
dérivé dans un document instance. La valeur de cet attribut est soit
la chaîne #all
soit une liste de valeurs parmi les
valeurs extension
et restriction
.
Les valeurs énumérées ou toutes pour #all
bloquent
les différents types qui peuvent remplacer le type pour un élément. La
valeur par défaut de cet attribut est donnée par la valeur de
l'attribut blockDefault
de l'élément
xsd:schema
.
Lorsque restriction
apparaît, par exemple,
dans la valeur de l'attribut block
de la définition
d'un type complexe, celui-ci ne peut pas être remplacé dans un document
par un type obtenu par restriction. Cette contrainte s'applique aux
substitutions de types et d'éléments. Il n'est pas possible de changer
le type d'un élément avec l'attribut xsi:type
.
Il n'est pas possible non plus de substituer l'élément par un autre
élément dont le type est
obtenu par restriction.
Dans le schéma suivant, les types Extension
et
Restriction
sont respectivement obtenus par
extension et restriction du type Base
. La
définition de ce type Base
contient
block="#all"
. Ceci impose que l'élément
value
ne peut pas changer son type en le type
Restriction
ou Restriction
avec
l'attribut xsi:type
. L'élément
subs
ne peut pas se substituer à l'élément
value
car son type est Extension
.
En revanche, l'élément sametype
peut se substituer à
l'élément value
car son type est
Base
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="value" type="Base"/> <!-- Élément du même type dans le groupe de substitution --> <xsd:element name="sametype" type="Base" substitutionGroup="value"/> <!-- Élément d'un type dérivé dans le groupe de substitution --> <xsd:element name="subst" type="Extension" substitutionGroup="value"/> ... <!-- Type de base ne pouvant pas être substitué dans les documents --> <xsd:complexType name="Base" block="#all"> <xsd:sequence> <xsd:element name="integer" type="xsd:integer"/> </xsd:sequence> </xsd:complexType> <!-- Type obtenu par extension du type de base --> <xsd:complexType name="Extension"> <xsd:complexContent> <xsd:extension base="Base"> <xsd:attribute name="att" type="xsd:string"/> </xsd:extension> </xsd:complexContent> </xsd:complexType> <!-- Type obtenu par restriction du type de base --> <xsd:complexType name="Restriction"> <xsd:complexContent> <xsd:restriction base="Base"> <xsd:sequence> <xsd:element name="integer" type="xsd:nonNegativeInteger"/> </xsd:sequence> </xsd:restriction> </xsd:complexContent> </xsd:complexType> </xsd:schema>
Le document suivant est valide pour le schéma précédent.
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?> <values xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <value> <integer>-1</integer> </value> <!-- Substitution autorisée avec le même type --> <sametype> <integer>-1</integer> </sametype> <!-- Élément substitué d'un type dérivé impossible --> <subst att="Un attribut"> <integer>-1</integer> </subst> <!-- Élément value de type Extension impossible --> <value xsi:type="Extension" att="Un attribut"> <integer>1</integer> </value> <!-- Élément value de type Restriction impossible --> <value xsi:type="Restriction"> <integer>1</integer> </value> </values>
Un type dérivé peut être contruit à partir d'un type de base en
utilisant plusieurs dérivations successives. Ceci peut être, par
exemple, une extension, ensuite une restriction puis finalement une
nouvelle extension. La substitution du type de base par le type
dérivé est bloquée si l'attribut block
, dans la
définition du type de base, mentionne une dérivation utilisée par le
type dérivé. Ceci est vrai que la dérivation bloquée soit la première
ou non. Dans l'exemple précédent, si l'attribut
block
contient restriction
, le
type dérivé ne peut pas remplacer le type de base car la seconde
dérivation est une restriction.
Dans le schéma suivant, le type List
bloque sa
substitution par un type obtenu par extension. Le type
ShortList
est obtenu par restriction du type
List
et le type AttrShortList
est
obtenu par extension du type ShortList
. Le type
ShortList
peut se substituer au type
List
. Au contraire, le type
AttrShortList
ne peut pas se substituer au type
List
car il y a une dérivation par extension entre
le type List
et le type
AttrShortList
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- Type de base ne pouvant pas être substitué par une extension --> <xsd:complexType name="List" block="extension"> <xsd:sequence> <xsd:element name="item" type="xsd:string" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> <!-- Restriction du type de base --> <xsd:complexType name="ShortList"> <xsd:complexContent> <xsd:restriction base="List"> <xsd:sequence> <!-- Nombre limité d'éléments item --> <xsd:element name="item" type="xsd:string" maxOccurs="8"/> </xsd:sequence> </xsd:restriction> </xsd:complexContent> </xsd:complexType> <!-- Extension de la restriction du type de base --> <xsd:complexType name="AttrShortList"> <xsd:complexContent> <xsd:extension base="ShortList"> <!-- Ajout d'un attribut --> <xsd:attribute name="length" type="xsd:integer"/> </xsd:extension> </xsd:complexContent> </xsd:complexType> <xsd:element name="list" type="List"/> </xsd:schema>
Le document suivant est valide pour le schéma précédent.
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?> <!-- Type ShortList possible mais type AttrShortList impossible --> <list xsi:type="ShortList" xsi:type="AttrShortList" length="3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <item>Premier item</item> <item>Deuxième item</item> <item>Troisième item</item> </list>
L'attribut block
peut aussi apparaître dans la
déclaration d'un élément. L'attribut block
de
l'élément xsd:element
permet d'empêcher
que cet élément puisse prendre un autre type dérivé dans un document
instance. La valeur de cet attribut est soit la chaîne
#all
soit une liste de valeurs parmi les valeurs
extension
, restriction
et
substitution
. Les valeurs énumérées ou toutes pour
#all
bloquent les différents types qui peuvent
remplacer le type pour un élément. La valeur par défaut de cet
attribut est donnée par la valeur de l'attribut blockDefault
de l'élément xsd:schema
.
Dans le schéma suivant, l'élément integer
bloque toutes les substitutions de types dans les documents avec
block="restriction extension"
. Ce blocage empêche
de changer le type en un type dérivé avec l'attribut xsi:type
. Il empêche également l'élément
positive
de se substituer à l'élément
integer
car son type est obtenu par restriction du
type xsd:integer
. En rechanche, l'élément
sametype
dont le type est aussi
xsd:integer
peut rempalcer l'élément
integer
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="integer" type="xsd:integer" block="restriction extension"/> <!-- Élément avec le même type --> <xsd:element name="sametype" type="xsd:integer" substitutionGroup="integer"/> <!-- Élément avec un type obtenu par restriction --> <xsd:element name="positive" type="xsd:positiveInteger" substitutionGroup="integer"/> ... </xsd:schema>
Le document suivant est valide pour le schéma précédent.
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?> <integers xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <integer>0</integer> <!-- Substitution par un élément de même type --> <sametype>1</sametype> <!-- Substitution de type impossible --> <integer xsi:type="xsd:positiveInteger">1</integer> <!-- Substitution d'élément avec un type dérivé impossible --> <positive>1</positive> </integers>
L'attribut block
de l'élément
xsd:element
peut aussi contenir la valeur
substitution
. Cette valeur a un effet très proche
de l'attribut final
avec la valeur
#all
. Elle empêche les éléments du groupe de
substitution de remplacer leur chef de groupe dans les documents
instance. Cela anihile l'intérêt de créer un groupe de substitution
puisque ses membres ne peuvent pas réellement se substituer à leur chef
de groupe.
Dans le schéma suivant, les éléments sametype
et positive
appartiennent au groupe de substitution
de l'élément integer
. En rechanche, ils ne peuvent pas
se substituer à cet élément en raison de la valeur
substitution
de l'attribut
block
. La substitution de type avec xsi:type
reste toujours possible.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="integer" type="xsd:integer" block="substitution"/> <!-- Élément avec le même type --> <xsd:element name="sametype" type="xsd:integer" substitutionGroup="integer"/> <!-- Élément avec un type obtenu par restriction --> <xsd:element name="positive" type="xsd:positiveInteger" substitutionGroup="integer"/> ... </xsd:schema>
Le document suivant est valide pour le schéma précédent.
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?> <integers xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <integer>0</integer> <!-- Substitution de type --> <integer xsi:type="xsd:positiveInteger">1</integer> <!-- Substitution d'élément avec le même type impossible --> <sametype>1</sametype> <!-- Substitution d'élément avec un type dérivé impossible --> <positive>1</positive> </integers>
Il est possible, dans un schéma, de restreindre l'utilisation
d'un type pour définir d'autres types. Ce mécanisme s'apparente à la
possiblité des langages de programmation orientés objet de bloquer la
dérivation d'une classe avec le qualificatif final
.
Le mécanisme des schémas est plus précis car il permet de bloquer
sélectivement les différentes dérivations : restriction, extension,
union et liste.
L'attribut final
des éléments xsd:simpleType
et xsd:complexType
permet d'empêcher que le type
défini puisse servir de type de base à des constructions ou à des
dérivations de types. Pour un type simple, la valeur de cet attribut
est soit la chaîne #all
soit une liste de valeurs
parmi les valeurs restriction
,
list
et union
. Il est donc
impossible de bloquer les extensions d'un type simple. Pour un type
complexe, la valeur de cet attribut est soit la chaîne
#all
soit une liste de valeurs parmi les valeurs
extension
, restriction
. Les
valeurs énumérées ou toutes pour #all
bloquent les
différentes façons de définir des nouveaux types. La valeur par défaut
de cet attribut est donnée par la valeur de l'attribut finalDefault
de l'élément xsd:schema
.
Le schéma suivant n'est pas correct car les définitions des types
Extension
et Restriction
sont
impossibles en raison de la valeur #all
de
l'attribut final
dans la définition du type
Base
. Si la valeur de cet attribut
final
est changée en restriction
,
la définition du type Restriction
reste incorrecte
mais la définition du type Extension
devient
valide.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> ... <!-- L'attribut final="#all" empêche les restrictions et extensions --> <xsd:complexType name="Base" final="#all"> <xsd:sequence> <xsd:element name="integer" type="xsd:integer"/> </xsd:sequence> </xsd:complexType> <!-- Extension du type Base impossible --> <xsd:complexType name="Extension"> <xsd:complexContent> <xsd:extension base="Base"> <xsd:attribute name="att" type="xsd:string"/> </xsd:extension> </xsd:complexContent> </xsd:complexType> <!-- Restriction du type Base impossible --> <xsd:complexType name="Restriction"> <xsd:complexContent> <xsd:restriction base="Base"> <xsd:sequence> <xsd:element name="integer" type="xsd:nonNegativeInteger"/> </xsd:sequence> </xsd:restriction> </xsd:complexContent> </xsd:complexType> </xsd:schema>
Le bloquage imposé par l'attribut final
n'opère que sur la dérivation directe de types. Dans le schéma
suivant, le type List
bloque les extensions avec
final="extension"
. Le type
ShortList
est dérivé par restriction du type
List
. Ce type peut être étendu en un type
AttrShortList
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- Type de base bloquant les extensions --> <xsd:complexType name="List" final="extension"> <xsd:sequence> <xsd:element name="item" type="xsd:string" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> <!-- Restriction du type de base --> <xsd:complexType name="ShortList"> <xsd:complexContent> <xsd:restriction base="List"> <xsd:sequence> <!-- Nombre limité d'éléments item --> <xsd:element name="item" type="xsd:string" maxOccurs="8"/> </xsd:sequence> </xsd:restriction> </xsd:complexContent> </xsd:complexType> <!-- Extension de la restriction du type de base --> <xsd:complexType name="AttrShortList"> <xsd:complexContent> <xsd:extension base="ShortList"> <!-- Ajout d'un attribut --> <xsd:attribute name="length" type="xsd:integer"/> </xsd:extension> </xsd:complexContent> </xsd:complexType> <xsd:element name="list" type="List"/> </xsd:schema>
Le document suivant est valide pour le schéma précédent.
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
<list length="3" xsi:type="AttrShortList"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<item>Premier item</item>
<item>Deuxième item</item>
<item>Troisième item</item>
</list>
La différence entre les attributs final
et
block
est que final
concerne la
définition de types dérivés alors que block
concerne
l'utilisation des types dérivés dans les documents instance.
Il est possible, dans un schéma, de limiter les éléments susceptibles de se substituer à un élément donné. Il est en effet possible d'empêcher sélectivement les éléments d'appartenir à un groupe de substitution en fonction de leur type.
L'attribut final
de l'élément xsd:element
permet de sélectioner quels éléments
peuvent appartenir au groupe de substitution de l'élément. La valeur
de cet attribut est soit la chaîne #all
soit une
liste de valeurs parmi les valeurs restriction
et
extension
. Les valeurs énumérées ou toutes pour
#all
bloquent les éléments dont le type est obtenu
par la dérivation correspondante.
Dans le schéma suivant, l'élément integer
empêche les éléments dont le type est dérivé par extension de son type
xsd:integer
d'appartenir à son groupe de
substitution. Comme le type xsd:positiveInteger
est
obtenu par restriction du type xsd:integer
,
l'élément positive
peut appartenir au groupe de
substitution de integer
. En revanche, l'élément
attributed
ne pourrait pas appartenir à ce groupe de
substitution car son type Attributed
est obtenu par
extension du type xsd:integer
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="integer" type="xsd:integer" final="extension"/> <!-- Élément avec un type obtenu par restriction de xsd:integer --> <xsd:element name="positive" type="xsd:positiveInteger" substitutionGroup="integer"/> <!-- Élément avec un type obtenu par extension de xsd:integer --> <!-- Impossible dans le groupe de substitution de integer --> <xsd:element name="attributed" type="Attributed" substitutionGroup="integer"/> <!-- Type obtenu par extension de xsd:integer --> <xsd:complexType name="Attributed"> <xsd:simpleContent> <xsd:extension base="xsd:integer"> <xsd:attribute name="att" type="xsd:string"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> ... </xsd:schema>
Le document suivant est valide pour le schéma précédent.
L'élément attributed
ne peut pas remplacer l'élément
integer
.
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?> <integers> <integer>0</integer> <!-- Substitution élément --> <positive>1</positive> <!-- Élément attributed impossible --> <attributed att="Un attribut">-1</attributed> </integers>
Il est possible de nommer des groupes d'éléments et des groupes
d'attributs afin de pouvoir les réutiliser. Ce mécanisme aide à
structurer un schéma complexe et vise à obtenir une meilleure modularité
dans l'écriture des schémas. Les groupes d'éléments et d'attributs sont
respectivement définis par les éléments xsd:group
et
xsd:attributeGroup
.
Les groupes d'éléments ne doivent pas être confondus avec les groupes de substitution qui permettent de remplacer un élément par un autre.
L'élément xsd:group
permet de définir un groupe
d'éléments dont le nom est donné par l'attribut name
.
L'élément xsd:group
doit être enfant de l'élément
racine xsd:schema
du schéma. Ceci
signifie que la portée de la définition du groupe est le schéma tout
entier. Le contenu de l'élément xsd:group
est un
fragment de type nécessairement inclus dans un élément
xsd:sequence
, xsd:choice
ou xsd:all
.
Un groupe peut être employé dans la définition d'un type ou la
définition d'un autre groupe. L'utilisation d'un groupe est équivalente
à l'insertion de son contenu. L'intérêt d'un groupe est de pouvoir
l'utiliser à plusieurs reprises et de factoriser ainsi les parties
communes à plusieurs types. L'utilisation d'un groupe est introduite
par un élément xsd:group
avec un attribut
ref
qui donne le nom du groupe à insérer.
Dans le schéma suivant, le groupe FirstLast
est
défini puis utilisé dans la définition du groupe Name
et du type Person
ainsi que dans la définition du
type anonyme de l'élément character
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:group name="FirstLast"> <xsd:sequence> <xsd:element name="firstname" type="xsd:string"/> <xsd:element name="lastname" type="xsd:string"/> </xsd:sequence> </xsd:group> <xsd:group name="Name"> <xsd:choice> <xsd:element name="name" type="xsd:string"/> <!-- Insertion du contenu du groupe FirstLast --> <xsd:group ref="FirstLast"/> </xsd:choice> </xsd:group> <xsd:complexType name="Person"> <xsd:sequence> <xsd:element name="surname" type="xsd:string" minOccurs="0"/> <!-- Insertion du contenu du groupe Name --> <xsd:group ref="Name"/> </xsd:sequence> </xsd:complexType> <xsd:element name="characters"> <xsd:complexType> <xsd:sequence> <xsd:element name="character" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <!-- Insertion du contenu du groupe Name --> <xsd:group ref="Name"/> <xsd:element name="creator" type="Person" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
Le document suivant est valide pour le schéma précédent.
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?> <characters> <character> <firstname>Gaston</firstname> <lastname>Lagaffe</lastname> <creator> <firstname>André</firstname> <lastname>Franquin</lastname> </creator> </character> <character> <name>Astérix</name> <creator> <surname>Al Uderzo</surname> <firstname>Albert</firstname> <lastname>Uderzo</lastname> </creator> <creator> <firstname>René</firstname> <lastname>Goscinny</lastname> </creator> </character>
Un groupe est en fait un fragment de type qui peut être utilisé à l'intérieur de la définition de n'importe quel type. En revanche, il ne peut pas servir comme type dans la déclaration d'un l'élément. À l'inverse, un type peut servir dans la déclaration d'éléments mais il ne peut pas être directement inclus par un autre type.
Les groupes sont en fait un mécanisme d'abréviation. Ils permettent d'accroître la modularité des schémas en évitant de recopier plusieurs fois le même fragment dans les définitions de différents types.
Les groupes d'attributs jouent, pour les attributs, un rôle
similaire aux groupes d'éléments. Ils permettent de regrouper plusieurs
déclarations d'attributs dans le but d'une réutilisation. L'élément
xsd:attributeGroup
permet de définir un groupe
d'attributs dont le nom est donné par l'attribut
name
. L'élément
xsd:attributeGroup
doit être enfant de l'élément
racine xsd:schema
du schéma. Ceci
signifie que la portée de la définition du groupe est le schéma tout
entier. Le contenu de l'élément xsd:attributeGroup
est constitué de déclarations d'attributs introduites par l'élément
xsd:attribute
.
Dans l'exemple suivant, le groupe d'attributs
LangType
regroupe les déclaration des deux attributs
lang
et type
.
<xsd:attributeGroup name="LangType"> <xsd:attribute name="lang" type="xsd:language"/> <xsd:attribute name="type" type="xsd:string"/> </xsd:attributeGroup>
Un groupe d'attributs peut être employé dans la définition d'un
type ou la définition d'un autre groupe d'attributs. L'utilisation d'un
groupe est équivalente à l'insertion de son contenu. L'utilisation d'un
groupe est introduite par un élément
xsd:attributeGroup
avec un attribut
ref
qui donne le nom du groupe à insérer.
Le groupe d'attributs LangType
peut être
employé de la façon suivante dans la définition d'un type complexe
nommé ou anonyme. Tout élément du type SomeType
défini ci-dessous pourra avoir les attributs lang
et
type
déclarés dans le groupe
LangType
.
<xsd:complexType name="SomeType">
<!-- Contenu -->
...
<xsd:attributeGroup ref="LangType"/>
</xsd:complexType>
Il est possible d'utiliser successivement plusieurs groupes
d'attributs pour déclarer les attributs d'un type mais il faut une
occurrence de xsd:attributeGroup
pour chaque groupe
utilisé.
<xsd:attributeGroup ref="AttrGroup1"/> <xsd:attributeGroup ref="AttrGroup2"/>
Un groupe d'attributs peut aussi être utilisé dans la définition d'un autre groupe d'attributs. Le nouveau groupe défini contient tous les attributs du ou des groupes référencés en plus des attributs qu'il déclare explicitement. Ce mécanisme est semblable à l'héritage des classes dans les langages de programmation orientés objet.
<xsd:attributeGroup name="LangTypeClass">
<xsd:attributeGroup ref="LangType"/>
<xsd:attribute name="class" type="xsd:string"/>
</xsd:attributeGroup>
Le schéma à l'adresse http://www.w3.org/2001/xml.xsd
déclare les quatre attributs
particuliers xml:lang
,
xml:space
, xml:base
et
xml:id
. Il définit également un groupe d'attributs
xml:specialAttrs
permettant de déclarer
simultanément ces quatre attributs. Un exemple d'utilisation de
celui-ci est donné dans la partie sur l'import de schémas. Cet exemple montre que
les noms des groupes d'éléments et des groupes d'attributs sont des noms
qualifiés dans l'espace de noms cible du schéma.
Les schémas permettent de spécifier des contraintes globales de
cohérence. Celles-ci doivent être vérifiées par un document pour
que celui-ci soit valide. Elles ressemblent aux contraintes des DTD
portant sur les attributs des types ID
,
IDREF
et IDREFS
mais
elles sont beaucoup plus générales. Elle peuvent porter sur des éléments
ou des attributs. La portée de ces contraintes peut être n'importe quel
contenu d'élément et non pas l'intégralité du document comme dans les
DTD.
Ces contraintes sont de deux types. Elles peuvent être des
contraintes d'unicité comme celle des attributs de
type ID
des DTD ou des contraintes
d'existence comme celle des attributs de type
IDREF
et IDREFS
des DTD. Les
contraintes utilisent des expressions XPath mais une connaissance superficielle de
ce langage suffit pour les utiliser.
Une contrainte d'unicité spécifie que dans le
contenu d'un élément donné, il ne peut exister qu'un seul élément ayant
une propriété fixée. Cette propriété est très souvent la valeur d'un
attribut mais elle peut aussi être formée des valeurs de plusieurs
enfants ou attributs. Cette notion est similaire à la notion de
clé des bases de données. Elle généralise les
attributs de types ID
dont la valeur est unique dans
tout le document.
Une contrainte d'unicité est donnée par un élément
xsd:key
ou xsd:unique
. Les
contraintes introduites par ces deux éléments se présentent de la même
façon et ont des sémantiques très proches. L'élément
xsd:key
ou xsd:unique
doit être
enfant d'un élément xsd:element
qui déclare un
élément. Cet élément qui contient la contrainte définit la
portée de celle-ci. Les contraintes d'unicité
ainsi que les contraintes d'existence doivent être placées après le type
de la déclaration.
Chaque élément xsd:key
ou
xsd:unique
possède un attribut
name
uniquement utilisé par les contraintes
d'existence introduites par xsd:keyref
et qui peut
donc être ignoré pour l'instant. Il contient un élément xsd:selector
et des éléments xsd:field
possédant chacun un attribut
xpath
. L'élément xsd:selector
détermine sur quels éléments porte la contrainte. La valeur de son
attribut xpath
est une expression XPath qui
sélectionne des éléments concernés. Les éléments
xsd:field
déterminent quelle est la valeur qui doit
être unique. Cette valeur est constituée de plusieurs
champs à la manière d'un objet dans les langages de
programmation. La valeur de l'attribut xpath
de
chacun des éléments xsd:field
spécifie un champ de
la valeur de la clé d'unicité. La contrainte donnée par un élément
xsd:key
impose que chacun des champs déterminé par
les éléments xsd:field
soit présent et que la valeur
ainsi constituée soit unique pour les éléments sélectionnés par
xsd:selector
dans le contenu de l'élément définissant
la portée. Au contraire, la contrainte donnée par un élément
xsd:key
n'impose pas que chacun des champs déterminé
par les éléments xsd:field
soit présent. Elle impose
seulement que les éléments ayant tous les champs aient une valeur
unique.
Dans l'exemple, la contrainte est décrite au niveau de l'élément
bibliography
pour exprimer que l'attribut
key
de book
doit être unique dans
le contenu de l'élément bibliography
.
<!-- Déclaration de l'élément bibliography de type Bibliography --> <xsd:element name="bibliography" type="Bibliography"> <!-- Unicité des attributs key des éléments book dans bibliography --> <xsd:key name="dummy"> <xsd:selector xpath="book"/> <xsd:field xpath="@key"/> </xsd:key> </xsd:element>
Une contrainte décrite avec xsd:key
implique
que les champs impliqués soient nécessairement présents et non annulables. Une contrainte
décrite avec xsd:unique
est au contraire seulement
vérifiée pour les éléments dont tous les champs spécifiés dans la
contrainte sont présents.
Le schéma suivant illustre la notion de portée. Il contient deux
exemples de contrainte d'unicité. Une première contrainte
group.num
porte sur les attributs
num
des éléments group
. Cette
contrainte est déclarée dans l'élément groups
qui
est l'élément racine du document ci-dessous. Deux éléments
group
du document ne peuvent pas avoir la même
valeur d'attribut num
. La seconde contrainte
person.id
porte sur les éléments
person
contenus dans un élément
group
. Comme cette contrainte est déclarée dans
l'élément group
, deux éléments
person
contenus dans le même élément
group
ne peuvent pas avoir la même valeur d'attribut
id
. En revanche, deux éléments
person
contenus dans des éléments
group
différents peuvent avoir la même valeur
d'attribut id
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="groups"> <xsd:complexType> <xsd:sequence> <xsd:element ref="group" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> <!-- Unicité des attributs num des éléments group --> <xsd:unique name="group.num"> <xsd:selector xpath="group"/> <xsd:field xpath="@num"/> </xsd:unique> </xsd:element> <xsd:element name="group"> <xsd:complexType> <xsd:sequence> <xsd:element name="person" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <xsd:element name="firstname" type="xsd:string"/> <xsd:element name="lastname" type="xsd:string"/> </xsd:sequence> <xsd:attribute name="id" type="xsd:string"/> </xsd:complexType> </xsd:element> </xsd:sequence> <xsd:attribute name="num" type="xsd:integer"/> </xsd:complexType> <!-- Unicité des attributs id des éléments person --> <xsd:key name="person.id"> <xsd:selector xpath="person"/> <xsd:field xpath="@id"/> </xsd:key> </xsd:element> </xsd:schema>
Le document suivant est valide pour le schéma précédent. Deux
éléments person
contenus respectivement dans le
premier et le deuxième élément group
ont la même
valeur AC
pour l'attribut
id
.
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?> <groups> <group num="1"> <person id="AC"> <firstname>Albert</firstname> <lastname>Cohen</lastname> </person> <person id="VH"> <firstname>Victor</firstname> <lastname>Hugo</lastname> </person> </group> <group num="2"> <person id="AC"> <firstname>Anders</firstname> <lastname>Celsius</lastname> </person> <person id="SH"> <firstname>Stephen</firstname> <lastname>Hawking</lastname> </person> </group> </groups>
La valeur qui détermine l'unicité peut être constituée de
plusieurs champs. Il suffit pour cela de mettre plusieurs éléments
xsd:field
dans l'élément xsd:key
ou xsd:unique
. Deux valeurs sont alors considérées
comme différentes si elles diffèrent en au moins un champ.
La contrainte person.names
ci-dessous peut
remplacer la contrainte person.id
du schéma
précédent. Elle impose alors que la valeur formée des contenus des
deux éléments fitstname
et
lastname
soit différente pour chacun des éléments
person
. Deux éléments person
contenus dans un même élément group
peuvent avoir le
même contenu textuel pour l'élément firstname
ou
pour l'élément lastname
mais pas pour les deux en
même temps.
<xsd:key name="person.names"> <xsd:selector xpath="person"/> <xsd:field xpath="firstname"/> <xsd:field xpath="lastname"/> </xsd:key>
La contrainte ci-dessus illustre aussi que la valeur peut aussi
être donnée par des éléments et pas seulement par des attributs. Le
document suivant vérifie la contrainte ci-dessus bien que deux éléments
person
dans le même élément group
aient la même valeur Albert
pour l'élément
firstname
. Deux éléments ayant exactement la même
valeur pour l'attribut id
sont aussi dans le même
élément group
mais la contrainte ne porte plus sur
cet attribut.
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?> <groups> <group num="1"> <person id="AC"> <firstname>Albert</firstname> <lastname>Cohen</lastname> </person> <person id="VH"> <firstname>Victor</firstname> <lastname>Hugo</lastname> </person> <person id="AC"> <firstname>Anders</firstname> <lastname>Celsius</lastname> </person> <person id="AE"> <firstname>Albert</firstname> <lastname>Einstein</lastname> </person> </group> </groups>
Il est bien sûr possible de mettre plusieurs contraintes dans un
même élément. Les deux contraintes person.id
et
person.names
pourraient être mises simultanément
dans l'élément group
comme ci-dessous.
<xsd:key name="person.id"> <xsd:selector xpath="person"/> <xsd:field xpath="@id"/> </xsd:key> <xsd:key name="person.names"> <xsd:selector xpath="person"/> <xsd:field xpath="firstname"/> <xsd:field xpath="lastname"/> </xsd:key>
Avec les contraintes données ci-dessus, le document précédent
n'est plus valide car deux éléments person
ont la
même valeur AC
pour leur attribut
id
.
Le schéma précédent illustre également la différence entre les
contraintes introduites par les éléments xsd:key
et
xsd:unique
. Une contrainte introduite par
xsd:key
impose que tous les champs de la valeur
soient présents. La contrainte person.id
impose
donc que l'attribut id
soit présent dans chaque
élément person
même si cet attribut est déclaré
optionnel. Au
contraire, une contrainte introduite par xsd:unique
n'impose pas que tous les champs de la valeurs soient présents. Seuls
les éléments ayant tous les champs sont pris en compte dans la
vérification de la contrainte. Deux éléments ayant tous les champs ne
peuvent avoir tous les champs égaux.
Les valeurs des attributs xpath
des éléments
xsd:selector
et xsd:field
sont
des expressions XPath restreintes.
L'expression XPath de xsd:selector
est relative à
l'élément dont la déclaration contient l'élément
xsd:unique
ou xsd:key
. Elle
sélectionne uniquement des éléments descendants de cet élément.
L'expression XPath de xsd:field
est relative aux
éléments sélectionnés par xsd:selector
. Elle
sélectionne uniquement des éléments ou des attributs descendants de ces
éléments.
Les seuls opérateurs autorisés dans les expressions XPath des
attributs xpath
de xsd:selector
et xsd:field
sont l'opérateur d'union '|'
et l'opérateur
de composition de chemins '/'
. L'opérateur
'|'
peut apparaître au niveau global mais pas à
l'intérieur d'une expression de chemins avec l'opérateur
'/'
. Les seuls axes autorisés dans ces expressions
XPath sont les axes child::
et
attribute::
dans leurs syntaxes abrégées
' '
et '@'
. L'axe
descendant::
peut, en outre, apparaître au début des
expressions de chemins dans sa syntaxe abrégée
'.//'
. Les filtres ne sont pas permis dans ces
expressions. La contrainte suivante impose, par exemple, que tous les
enfants ainsi que tous les enfants de ses enfants
group
aient des valeurs d'attribut
id
différentes.
<xsd:unique name="all.id"> <xsd:selector xpath="* | group/*"/> <xsd:field xpath="id"/> </xsd:unique>
Une contrainte d'existence spécifie que dans
le contenu d'un élément donné, il doit exister un élément ayant une
propriété fixée. Comme pour les contraintes d'unicité, cette propriété
est très souvent la valeur d'un attribut mais elle peut aussi être
formée des valeurs de plusieurs enfants ou attributs. L'idée générale
est de référencer un élément par une valeur appelée
clé et que cet élément doit exister. Cette idée
généralise les attributs de types IDREF
et
IDREFS
des DTD.
Ces contraintes sont introduites par un élément
xsd:keyref
qui doit être enfant d'un élément xsd:element
. Comme pour les contraintes
d'unicité, cet élément dans lequel se trouve la contrainte définit la
portée de celle-ci.
Chaque élément xsd:keyref
possède des attributs
name
et refer
. L'attribut
name
donne le nom de la contrainte. La valeur de
l'attribut refer
doit être le nom, c'est-à-dire la
valeur de l'attribut name
, d'une contrainte d'unicité
qui est associée à cette contrainte d'existence. L'élément
xsd:keyref
contient un élément xsd:selector
et des éléments xsd:field
possédant chacun un attribut
xpath
. L'élément xsd:selector
sélectionne sur quels éléments porte la contrainte. La valeur de son
attribut xpath
est une expression XPath qui
sélectionne des éléments concernés. Les éléments
xsd:field
déterminent les différents champs de la
valeur servant de clé. La contrainte donnée par un élément
xsd:keyref
impose que pour chaque élément
sélectionné, il existe un élément sélectionné par la contrainte
d'unicité associée qui a la même valeur. La contrainte d'unicité
reférencée par l'attribut refer
doit se trouver
dans le même élément que xsd:keyref
ou dans
un de ses descendants.
Dans l'exemple suivant, la contrainte d'unicité
idchapter
impose que la valeur d'un attribut
id
d'un élément chapter
soit
unique. La contrainte d'existence idref
utilise
cette contrainte idchapter
pour imposer que la valeur
d'un attribut idref
de tout élément
ref
soit aussi la valeur d'un attribut
id
d'un élément chapter
. Ceci
signifie que tout élément ref
référence, par son
attribut idref
, un chapitre qui existe bien dans
le document.
<!-- Unicité des attributs id des éléments chapter --> <xsd:key name="idchapter"> <xsd:selector xpath="chapter"/> <xsd:field xpath="@id"/> </xsd:key> <!-- Existence des références idref des éléments ref --> <xsd:keyref name="idref" refer="idchapter"> <xsd:selector xpath=".//ref"/> <xsd:field xpath="@idref"/> </xsd:keyref>
Dans l'exemple précédent, la valeur d'un des attributs
xpath
est l'expression .//ref
qui
sélectionne tous les descendants de nom ref
de
l'élément courant. Cette expression est en fait une abréviation de l'expression
./descendant-or-self::node()/ref
.
Voici un exemple de document XML représentant une liste de commandes. Chaque commande concerne un certain nombre d'articles qui sont référencés dans le catalogue donné à la fin.
<?xml version="1.0" encoding="iso-8859-1"?> <list period="P2D"> <orders> <order date="2008-01-08" time="17:32:28"> <product serial="101-XX" number="12"/> <product serial="102-XY" number="23"/> <product serial="101-ZA" number="10"/> </order> <order date="2008-01-09" time="17:32:28"> <product serial="101-XX" number="32"/> </order> <order date="2008-01-09" time="17:32:29"> <product serial="101-XX" number="32"/> </order> </orders> <catalog> <product serial="101-XX">Product n° 1</product> <product serial="101-ZA">Product n° 2</product> <product serial="102-XY">Product n° 3</product> <product serial="102-XA">Product n° 4</product> </catalog> </list>
Le schéma correspondant impose trois contraintes suivantes sur le fichier XML.
Deux commandes order
n'ont pas la même date
et la même heure.
Deux produits du catalogue n'ont pas le même numéro de série.
Tous les produits référencés dans les commandes sont présents dans le catalogue.
Le début de ce schéma XML est le suivant.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="list"> <xsd:complexType> <xsd:sequence> <xsd:element name="orders" type="Orders"/> <xsd:element name="catalog" type="Catalog"/> </xsd:sequence> <xsd:attribute name="period" type="xsd:duration"/> </xsd:complexType> <!-- Unicité du couple (date,heure) --> <xsd:unique name="dummy"> <xsd:selector xpath="orders/order"/> <xsd:field xpath="@date"/> <xsd:field xpath="@time"/> </xsd:unique> <!-- Unicité du numéro de série --> <xsd:key name="serial"> <xsd:selector xpath="catalog/product"/> <xsd:field xpath="@serial"/> </xsd:key> <!-- Existence dans le catalogue de tout produit commandé --> <xsd:keyref name="unused" refer="serial"> <xsd:selector xpath="orders/order/product"/> <xsd:field xpath="@serial"/> </xsd:keyref> </xsd:element> <!-- Suite du schéma --> ...
Un des avantages des schémas par rapport aux DTD est la prise en
charge des espaces de noms.
L'attribut targetNamespace
de l'élément
xsd:schema
permet de préciser l'espace de
noms des éléments et des types définis par le schéma.
Pour une utilisation plus simple, il est possible d'ignorer les
espaces de noms. Il est alors possible de valider des documents dont
tous les éléments n'ont pas d'espace de noms. Il suffit, pour cela, que
les noms des éléments du document ne soient pas qualifiés (sans le
caractère ':'
) et que l'espace de noms par défaut ne
soit pas spécifié.
Si l'attribut targetNamespace
de l'élément
xsd:schema
est absent, tous les éléments et types
définis dans le schéma sont sans espace de noms. Il faut cependant
déclarer l'espace de noms des schémas pour qualifier les éléments des
schémas (xsd:element
,
xsd:complexType
, …).
Pour spécifier un espace de noms cible dans lequel sont définis
les éléments, l'attribut targetNamespace
de l'élément
xsd:schema
doit contenir l'URI associé à cet espace de noms. La valeur de
l'attribut elementFormDefault
de
l'élément xsd:schema
détermine quels éléments sont
effectivement définis dans l'espace de noms.
La valeur par défaut de l'attribut
elementFormDefault
est unqualified
. Quand la valeur de
elementFormDefault
est
unqualified
, seuls les éléments définis globalement,
c'est-à-dire quand l'élément xsd:element
est
directement enfant de l'élément xsd:schema
sont dans
l'espace de noms cible. Les autres éléments sont sans espace de
noms. Dans le schéma suivant, l'élément global name
est dans l'espace de noms identifié par l'URI
http://www.omega-one.org/~carton/
alors que les deux
éléments locaux firstname
et
lastname
sont sans espace de noms.
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- unqualified est la valeur par défaut de elementFormDefault -->
<xsd:schema targetNamespace="http://www.omega-one.org/~carton/"
elementFormDefault="unqualified"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="name">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="firstname" type="xsd:string"/>
<xsd:element name="lastname" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Le document suivant est valide pour le schéma précédent.
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?> <tns:name xmlns:tns="http://www.omega-one.org/~carton/"> <firstname>Gaston</firstname> <lastname>Lagaffe</lastname> </tns:name>
Si la valeur de l'attribut elementFormDefault
est qualified
, tous les éléments sont dans l'espace
de noms cible. Dans le schéma suivant, les trois éléments
name
, firstname
et
lastname
sont dans l'espace de noms
http://www.omega-one.org/~carton/
.
<?xml version="1.0" encoding="iso-8859-1"?>
<xsd:schema targetNamespace="http://www.omega-one.org/~carton/"
elementFormDefault="qualified"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="name">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="firstname" type="xsd:string"/>
<xsd:element name="lastname" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Le document suivant est valide pour le schéma précédent.
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?> <tns:name xmlns:tns="http://www.omega-one.org/~carton/"> <tns:firstname>Gaston</tns:firstname> <tns:lastname>Lagaffe</tns:lastname> </tns:name>
Le comportement pour les attributs est identique mais il est
gouverné par l'attribut attributeFormDefault
de
l'élément xsd:schema
. La valeur par défaut de cet
attribut est aussi unqualified
.
Les éléments et attributs définis globalement sont toujours dans
l'espace de noms cible. Pour les éléments et attributs locaux, il est
possible de changer le comportement dicté par
elementFormDefault
et
attributeFormDefault
en utilisant l'attribut
form
des éléments xsd:element
et
xsd:attribute
. Cet attribut peut prendre les valeurs
qualified
ou unqualified
. Le
schéma suivant spécifie que l'élément firstname
doit
être qualifié. Tous les autres éléments locaux comme
lastname
n'ont pas à être qualifiés car la valeur par
défaut de l'attribut elementFormDefault
est
unqualified
.
<?xml version="1.0" encoding="iso-8859-1"?>
<xsd:schema targetNamespace="http://www.omega-one.org/~carton/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="name">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="firstname" type="xsd:string" form="qualified"/>
<xsd:element name="lastname" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Le document suivant est valide pour le schéma précédent.
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?> <tns:name xmlns:tns="http://www.omega-one.org/~carton/"> <tns:firstname>Gaston</tns:firstname> <lastname>Lagaffe</lastname> </tns:name>
Lorsqu'un élément, un
attribut, un groupe d'éléments, un groupe
d'attributs ou encore un type défini globalement est référencé
par un attribut ref
ou type
, la valeur de cet attribut doit contenir le
nom qualifié. Ceci oblige à associer un préfixe à l'espace de noms
cible et à l'utiliser pour qualifier l'élément ou le type référencé
comme dans le schéma suivant.
Les éléments, attributs, groupes et types doivent être nommés avec
un nom non qualifié quand ils sont déclarés ou définis. Ils sont à ce
moment implicitement qualifiés par l'espace de nom cible. Ceci signifie
que les noms apparaissant dans l'attribut name
de
xsd:element
, xsd:attribute
,
xsd:group
, xsd:attributeGroup
,
xsd:simpleType
et xsd:complexType
sont toujours des noms locaux, c'est-à-dire sans préfixe.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema targetNamespace="http://www.omega-one.org/~carton/" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.omega-one.org/~carton/"> <!-- Référence au type Name par son nom qualifié --> <!-- Le nom name de l'élément déclaré n'est pas qualifié --> <xsd:element name="name" type="tns:Name" /> <!-- Le nom Name du type défini n'est pas qualifié --> <xsd:complexType name="Name"> <xsd:sequence> <xsd:element name="firstname" type="xsd:string"/> <xsd:element name="lastname" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:schema>
Dans l'exemple précédent, le type Name
est
référencé par son nom qualifié dans la déclaration de l'élément
name
. De la même façon, toute référence à un élément
déclaré globalement ou à un groupe d'éléments ou d'attributs utilise un
nom qualifié. Dans l'exemple suivant, l'élément name
apparaît dans la définition d'un autre type Tree
qui
pourrait être ajoutée au schéma précédent. La définition de ce type est
récursive et la référence à lui-même utilise bien sûr le nom
qualifié.
<?xml version="1.0" encoding="utf-8"?> <xsd:schema targetNamespace="http://www.omega-one.org/~carton/" xmlns:tns="http://www.omega-one.org/~carton/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- Déclaration des éléments globaux name et tree --> <xsd:element name="name" type="xsd:string"/> <!-- Référence au type Tree par son nom qualifié --> <xsd:element name="tree" type="tns:Tree"/> <xsd:complexType name="Tree"> <xsd:sequence> <!-- Référence à l'élément global name par son nom qualifié --> <xsd:element ref="tns:name"/> <!-- Référence récursive au type Tree par son nom qualifié --> <!-- Le nom child de l'élément déclaré n'est pas qualifié --> <xsd:element name="child" type="tns:Tree" minOccurs="0" maxOccurs="2"/> </xsd:sequence> </xsd:complexType> </xsd:schema>
L'utilisation de minOccurs
avec la
valeur 0
pour l'élément child
est
indispensable pour terminer la récursivité. Sinon, aucun document
valide ne peut avoir d'élément de type Tree
. Le
document suivant est valide pour le schéma précédent. Les éléments
globaux tree
et name
doivent être
qualifiés dans le document alors que l'élément local
child
ne doit pas l'être.
<?xml version="1.0" encoding="iso-8859-1"?> <tns:tree xmlns:tns="http://www.omega-one.org/~carton/"> <tns:name>Racine</tns:name> <child> <tns:name>Fils Gauche</tns:name> <child><tns:name>Petit fils</tns:name></child> </child> <child><tns:name>Fils Droit</tns:name></child> </tns:tree>
Il est souvent assez lourd de qualifier chacun des noms des objets
définis dans le schéma. Une alternative assez commode consiste à rendre
l'espace de noms par défaut égal à l'espace de noms cible comme dans
l'exemple suivant. Ceci impose bien sûr de ne pas utiliser l'espace de
noms par défaut pour les éléments des schémas comme il pourrait être
tentant de le faire. Dans la pratique, on associe l'espace de noms par
défaut à l'espace de noms cible et on déclare également un préfixe pour
cet espace de noms afin de pouvoir y faire référence de façon explicite.
Dans l'exemple suivant, l'espace de noms cible identifié par l'URI
http://www.omega-one.org/~carton/
est déclaré comme
l'espace de noms par défaut et il est également associé au préfixe
tns
.
<?xml version="1.0" encoding="iso-8859-1"?> <xsd:schema targetNamespace="http://www.omega-one.org/~carton/" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.omega-one.org/~carton/" xmlns:tns="http://www.omega-one.org/~carton/"> <!-- Référence au type Name par son nom qualifié --> <xsd:element name="name" type="Name" /> <!-- Définition du type Name --> <xsd:complexType name="Name"> <xsd:sequence> <xsd:element name="firstname" type="xsd:string"/> <xsd:element name="lastname" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:schema>
Dans un souci de modularité, il est possible d'importer d'autres
schémas dans un schéma à l'aide des éléments
xsd:include
et xsd:import
.
L'élément xsd:include
est employé lorsque l'espace de
noms cible est identique pour le schéma importé. L'élément
xsd:import
est employé lorsque l'espace de noms cible
du schéma importé est différent de celui qui réalise l'import. Les deux
éléments xsd:include
et xsd:import
possèdent un attribut schemaLocation
pour donner l'URL
du schéma. L'élément xsd:import
a, en outre, un
attribut namespace
pour spécifier l'URI qui identifie
l'espace de noms cible du schéma importé.
Le schéma à l'adresse http://www.w3.org/2001/xml.xsd
contient les définitions des quatre attributs particuliers xml:lang
, xml:space
, xml:base
et xml:id
de l'espace de noms XML. Le
schéma suivant importe ce schéma et utilise le groupe d'attributs
xml:specialAttrs
pour ajouter des
attributs à l'élément name
.
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.omega-one.org/~carton/"> <xsd:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/> <xsd:element name="name"> <xsd:complexType> <xsd:simpleContent> <!-- Le contenu est purement textuel --> <xsd:extension base="xsd:string"> <!-- L'élément name a les attributs xml:lang, xml:space ... --> <xsd:attributeGroup ref="xml:specialAttrs"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element> </xsd:schema>
Un document valide pour ce schéma est le suivant. L'espace de noms
XML est toujours associé au
préfixe xml
et il n'a pas besoin d'être déclaré.
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
<tns:name xml:lang="fr" xmlns:tns="http://www.omega-one.org/~carton/">
Élément avec un attribut xml:lang
</tns:name>
Une expression rationnelle désigne un ensemble de chaînes de
caractères. Une chaîne donnée est conforme à une
expression si elle fait partie des chaînes décrites. Les expressions
rationnelles sont construites à partir des caractères et des opérateurs
d'union '|'
, de concaténation et
de répétition '?'
, '*'
et '+'
.
La syntaxe des expressions rationnelles des schémas est inspirée de
celle du langage Perl avec cependant quelques variations. Elle diffère
de la syntaxe utilisée par les DTD pour décrire les contenus purs d'éléments car la
concaténation n'est plus marquée par la virgule ','
.
Ces expressions rationnelles sont utilisées par la facette xsd:pattern
pour
définir des restrictions de types simples. Elles sont également
utilisées, en dehors des schémas, par les fonctions XPath
matches()
, replace()
et tokenize()
ainsi
que l'élément XSLT xsl:analyze-string
.
La plupart des caractères se désignent eux-mêmes dans une
expression. Ceci signifie que l'expression 'a'
(sans
les apostrophes) désigne l'ensemble réduit à l'unique chaîne
'a'
(sans les apostrophes). Certains caractères, dits
spéciaux, ont une signification particulière dans
les expressions. La liste des caractères spéciaux comprend les
caractères '|'
, '?'
,
'*'
, '+'
, '.'
,
'\'
, '('
, ')'
,
'['
, ']'
, '{'
,
'}'
. Pour supprimer le caractère spécial d'un de ces
caractères et l'inclure dans une expression, il faut le faire précéder du
caractère d'échappement '\'
. Quelques caractères d'espacement
bénéficient de notations spécifiques. La tabulation
U+09
, le saut de ligne U+0A
et le
retour chariot U+0D
peuvent être désignés par
'\t'
, '\n'
et
'\r'
. Ces notations ne sont pas indispensables
puisque ces trois caractères peuvent être insérés dans un document XML
avec la notation &#...
.
Les principaux opérateurs des expressions rationnelles sont
l'union désignée par le caractère '|'
, la
concaténation notée par simple juxtaposition et les opérateurs de
répétition '?'
, '*'
,
'+'
. Comme pour les expressions arithmétiques, on
peut utiliser les parenthèses '('
et
')'
pour former des groupes. Une expression de la
forme
désigne l'union des ensembles de chaînes désignés par
expr-1
|expr-2
expr-1
et expr-2
.
L'expression a|b
désigne, par exemple, l'ensemble
contenant les deux chaînes 'a'
et
'b'
(sans les apostrophes). Une expression de la
forme
désigne l'ensemble des chaînes obtenues en concaténant (c'est-à-dire en
mettant bout à bout) une chaîne conforme à l'expression
expr-1
expr-2
expr-1
et une chaîne conforme à l'expression
expr-2
. L'expression ab
désigne, par exemple, l'ensemble contenant l'unique chaîne
ab
. Il est, bien sûr, possible de combiner ces
opérateurs. L'expression aba|ba
désigne, par
exemple, l'ensemble formé des deux chaînes aba
et
ba
. L'expression a(a|b)bc
désigne
l'ensemble contenant les deux chaînes aabc
et
abbc
.
Les opérateurs '?'
, '*'
,
'+'
permettent de répéter des groupes. Ils utilisent
une notation postfixée : ils se placent après leur opérande. S'ils sont
placés après un caractère, ils s'appliquent uniquement à celui-ci mais
s'ils sont placés après un groupe entre parenthèses, ils s'appliquent à
tout le groupe. Ils autorisent, respectivement, la répétition de leur
opérande, zéro ou une fois, un nombre quelconque de fois et un nombre
positif de fois. Une expression de la forme
désigne l'ensemble
constitué de la chaîne vide et des chaînes conformes à l'expression
expr
?expr
. Une expression de la forme
désigne l'ensemble
constitué de toutes les chaînes obtenues en concaténant plusieurs
(éventuellement zéro) chaînes conformes à l'expression
expr
*expr
. L'expression a?
désigne, par exemple, l'ensemble formé de la chaîne vide et de la chaîne
'a'
. Les expressions a*
et
(a|b)*
désignent, respectivement, les ensembles
constitués des chaînes formées uniquement de 'a'
et
les chaînes formées de 'a'
et de
'b'
.
Les accolades '{'
et '}'
permettent d'exprimer des répétitions dont le nombre est, soit un entier
fixé, soit dans un intervalle donné. Une expression de la forme
,
où expr
{n
}n
est un entier, désigne l'ensemble
constitué de toutes les chaînes obtenues en concaténant exactement
n
chaînes conformes à l'expression
expr
. Une expression de la forme
,
où expr
{m
,n
}m
et n
sont des
entiers, désigne l'ensemble constitué de toutes les chaînes obtenues en
concaténant un nombre de chaînes conformes à l'expression
expr
compris, au sens large, entre
m
et n
. L'entier
n
peut être omis pour donner une expression
de la forme
.
Le nombre de répétitions doit seulement être supérieur à
expr
{m
,}m
. L'expression (a|b){6}
désigne, par exemple, les chaînes de longueur 6 formées de
'a'
et de 'b'
. L'expression
(a|b){3,8}
désigne les chaînes de longueur comprise
entre 3 et 8 formées de 'a'
et de
'b'
.
Il est souvent nécessaire de désigner des ensembles de caractères pour construire des expressions rationnelles. Il existe plusieurs façons de décrire ces ensembles.
Le caractère spécial '.'
désigne
tout caractère autre qu'un retour à la ligne. L'expression
a.b
désigne, par exemple, l'ensemble de toutes les
chaînes de trois caractères dont le premier est 'a'
,
le second n'est pas un retour à la ligne et le dernier est
'b'
. L'expression .*
désigne
l'ensemble de toutes les chaînes ne contenant aucun retour à la
ligne.
Un ensemble fini de caractères peut simplement être décrit en
donnant ces caractères encadrés par des crochets '['
et ']'
. L'expression [aeiouy]
désigne l'ensemble des voyelles minuscules et elle est équivalente à
l'expression a|e|i|o|u|y
. Cette syntaxe est pratique
car elle permet d'inclure facilement un intervalle en plaçant un tiret
'-'
entre les deux caractères qui le délimitent.
L'expression [0-9]
désigne, par exemple, l'ensemble
des chiffres. Il est possible de mettre des caractères et plusieurs
intervalles. L'expression [:a-zA-F]
désigne
l'ensemble des lettres minuscules et majuscules et du caractère
':'
. L'ordre des caractères entre les crochets est
sans importance. Pour inclure un tiret '-'
dans
l'ensemble, il faut le placer en premier ou en dernier. Pour inclure un
crochet fermant ']'
, il faut le placer en premier,
juste après le crochet ouvrant. L'expression [-az]
désigne l'ensemble des trois caractères '-'
,
'a'
et'z'
.
Lorsque le premier caractère après le crochet ouvrant est le
caractère '^'
, l'expression désigne le complémentaire
de l'ensemble qui aurait été décrit sans le caractère
'^'
. L'expression [^0-9]
désigne,
par exemple, l'ensemble des caractères qui ne sont pas un chiffre. Pour
inclure un caractère '^'
dans l'ensemble, il faut le
placer à une autre place que juste après le crochet ouvrant.
L'expression [0-9^]
désigne, par exemple, l'ensemble
formé des chiffres et du caractère '^'
.
Un ensemble de caractères peut être décrit comme la différence de
deux ensembles entre crochets. La syntaxe prend la forme
[...-[...]]
où ...
est remplacé
par une suite de caractères et d'intervalles comme dans les exemples
précédents. L'expression [a-z-[aeiouy]]
désigne, par
exemple, l'ensemble des consonnes minuscules.
Certains ensembles de caractères fréquemment utilisés peuvent être
décrits par le caractère d'échappement '\'
suivi d'une
lettre. Les différentes combinaisons possibles sont données
ci-dessous.
\s
caractères
d'espacement, c'est-à-dire l'ensemble
[ \t\n\r]
\S
caractères autres que les caractères d'espacement, c'est-à-dire
l'ensemble [^ \t\n\r]
\d
chiffres, c'est-à-dire [0-9]
\D
caractères autres que les chiffres, c'est-à-dire
[^0-9]
\w
caractères alphanumériques et le tiret '-'
,
c'est-à-dire [-0-9a-zA-Z]
\W
caractères autres que les caractères alphanumériques et le tiret,
c'est-à-dire [^-0-9a-zA-Z]
\i
premiers caractères des noms XML, c'est-à-dire
[:_a-zA-Z]
\I
caractères autres que les premiers caractères des
noms XML, c'est-à-dire [^:_a-zA-Z]
\c
caractères des noms
XML, c'est-à-dire [-.:_0-9a-zA-Z]
\C
caractère autres que les caractères des noms XML,
c'est-à-dire [^-.:_0-9a-zA-Z]
L'expression \s*\d+\s*
désigne, par exemple,
une suite non vide de chiffres encadrée, éventuellement, par des
caractères d'espacement. L'expression \i\c*
désigne
l'ensemble des noms XML.
Il est aussi possible de décrire un ensemble de caractères en
utilisant une des catégories de caractères Unicode. La syntaxe prend la
forme \p{
pour
l'ensemble des caractères de la catégorie cat
}cat
et \P{
pour son
complémentaire. L'expression cat
}\p{Lu}
désigne, par
exemple, toutes les lettres majuscules. Les principales catégories de
caractères Unicode sont les suivantes.
Catégorie | Signification | |
---|---|---|
L | lettres | |
Lu | lettres majuscules | |
Ll | lettres minuscules | |
N | chiffres | |
P | caractère de ponctuation | |
Z | Séparateurs |
Tableau 5.1. Catégories Unicode