FAQ XML
FAQ XMLConsultez toutes les FAQ
Nombre d'auteurs : 5, nombre de questions : 65, dernière mise à jour : 16 juin 2021
- Qu'est-ce que XML Schema ?
- XML Schema ou DTD ?
- Comment attacher un (ou plusieurs) XSD à un document XML ?
- Est-il possible de spécifier des entités dans un XML Schema ?
- Comment s'utilise l'attribut nillable ?
- Comment permettre à un élément d'être vide, tout en appliquant un typage à son éventuelle valeur ?
- Existe-t-il un équivalent de xsd:choice pour les attributs ?
- Existe-t-il un équivalent de xsd:sequence pour les attributs ?
- Est-il possible de demander les éléments dans le désordre ?
- Est-il possible de faire dépendre le nombre d'élément [éventuellement d'un élément en particulier] dans les fils d'un éléments ?
- Est-il possible de faire des choix "complexe" entre les attributs ?
- Est-il possible de faire dépendre le contenu d'un élément de la valeur d'un attribut ?
- Est-il possible de ne pas définir de type spécifique pour un élément ?
XSD (XML Schema Document) ou WXS ((W3C) XML Schemas) désignent la norme XML Schemas du W3C.
Il s'agit d'une norme XML qui est utilisée pour décrire une structure de documents XML.
Un XML Schema (ou XSD, en référence à l'extension qui leur est généralement attribuée), permet de définir une structure de document XML, un format de document XML.
Tout document XML respectant cette structure et référençant le XML Schema est alors déclaré valide.
La définition de la structure peut-être très fine, et très précise. De plus, les XSD sont des Documents XML, donc tous les outils de manipulations de documents XML peuvent y être appliqués.
Lien : La Norme XML Schema du W3C
Les "anciens" DocType (DTD : Document Type Definition) permettaient déjà de définir une structure pour un fichier XML, cependant, la norme XML Schema est destinée à les remplacer pour plusieurs raison :
- Les XML Schemas sont des documents XML, de ce fait, tous les outils (validateurs, parseurs, processeurs, ...) mais également scripts et langages (XSLT, XPath, ...) qui permettent de travailler les Documents XML sont utilisables sur des XSD.
- Les XML Schemas permettent des gestion beaucoup plus fines de la structure des documents : ordre (ou désordre) des éléments fils, nombre d'occurrences d'un élément, gestion très précise des types de données contenu par les éléments et les attributs (possibilité d'appliquer des expressions régulière sur les données, ou des types à fort valeur sémantiques tels que le type date), ...
- Il est possible d'utiliser et de faire interagir très facilement des XSD entre eux.
Attacher un ou plusieurs XSD à un XML est plus complexe que pour un DTD. Dans un document XML, la partie d'un document qui est soumise à un XSD se nomme un Espace de Noms (NameSpace), en général, ils sont spécifiés sous la forme d'une URL. Les namespace sont déclarés avec l'attribut xmlns ou xmlns:* où "*" représente le préfixe associé au namespace... Une balise ou un attribut entre dans le cadre d'un namespace si son nom est précédé du préfixe associé au namespace suivi de ':', ou si le nom n'a pas de préfixe dans le cas du namespace par défaut (celui précisé avec xmlns). Ensuite l'attribut xsi:schemaLocation permet de spécifier le XSD associé à un namespace. Ensuite, chaque balise ou attribut spécifié comme étant dans ce namespace est soumis à la validation du XSD.
Voici un cas simple où il n'y a qu'un seul XSD entrant en jeu, et donc qu'un seul namespace :
<?xml version="1.0" ?>
<rootelement
xmlns
=
"http://www.example.com/MyXMLNS/"
xmlns
:
xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi
:
schemaLocation
=
"http://www.example.com/MyXMLNS/ http://www.example.com/MyXMLNS/XMLSchema.xsd"
>
[...]
</rootelement>
Mais voici ensuite trois cas plus complexes et équivalents mettant en jeux le namespace XHTML... Comme vous pourrez le constater, un namespace existe pour la balise sur laquelle il est définit, et pour toutes les balises contenues dans celle-ci, à moins qu'une de ces balises ne définisse un nouveau namespace pour ce préfix (dans ce cas le schema se répète avec le nouveau namespace). De plus, on n'est pas obligé de spécifier un XSD pour un namespace. Bien entendu, le XSD du namespace http://www.example.com/MyXMLNS/ indique que son élément content doit contenir un élément div du namespace XHTML...
<?xml version="1.0" ?>
<rootelement
xmlns
=
"http://www.example.com/MyXMLNS/"
xmlns
:
xhtml
=
"http://www.w3.org/1999/xhtml"
xmlns
:
xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi
:
schemaLocation
=
"http://www.example.com/MyXMLNS/ http://www.example.com/MyXMLNS/XMLSchema.xsd"
>
[...]
<content>
<
xhtml
:
div>
[...] <!-- namespace XHTML -->
</
xhtml
:
div>
</content>
</rootelement>
<?xml version="1.0" ?>
<rootelement
xmlns
=
"http://www.example.com/MyXMLNS/"
xmlns
:
xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi
:
schemaLocation
=
"http://www.example.com/MyXMLNS/ http://www.example.com/MyXMLNS/XMLSchema.xsd"
>
[...]
<content>
<
xhtml
:
div
xmlns
:
xhtml
=
"http://www.w3.org/1999/xhtml"
>
[...] <!-- namespace XHTML -->
</
xhtml
:
div>
</content>
</rootelement>
<?xml version="1.0" ?>
<rootelement
xmlns
=
"http://www.example.com/MyXMLNS/"
xmlns
:
xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi
:
schemaLocation
=
"http://www.example.com/MyXMLNS/ http://www.example.com/MyXMLNS/XMLSchema.xsd"
>
[...]
<content>
<div
xmlns
=
"http://www.w3.org/1999/xhtml"
>
[...] <!-- namespace XHTML -->
</div>
</content>
</rootelement>
Ce n'est pas exactement possible comme on le faisait pour un DTD. Cependant, il existe deux solutions (recommandée par le W3C) qui permet de simuler ce comportement :
La première consiste a insérer un DTD contenant la dite entité au début du XML :
<?xml version="1.0" ?>
<!DOCTYPE root [
<!ENTITY eacute
"é"
>
<!ENTITY egrave
"è"
>
]>
<root
xmlns
=
"http://www.exemple.com/XMLNameSpace"
>
<!-- etc... -->
<town>
Mollé
g&eagrave;
s</town>
<!-- etc... -->
</root>
Bien sûr, ceci est un peu pénible car il faut le spécifier au début de chaque document XML.
D'où la deuxième solution, elle permet de simuler une entité en déclarant une balise à contenu fixe approprié :
<
xsd
:
element
name
=
"eacute"
type
=
"xsd:token"
fixed
=
"é"
/>
Pour l'utiliser ensuite dans le document XML, il suffit de le faire ainsi (pour des raisons de lisibilité, nous avons préférer retrancher les pseudo-entitées dans un XSD séparé :
<?xml version="1.0" ?>
<root
xmlns
=
"http://www.exemple.com/XMLNameSpace"
xmlns
:
E
=
"http://www.exemple.com/Entites>
<!-- etc... -->
<town>Moll<E:eacute/>g<E:eagrave/>s</town>
<!-- etc... -->
</root>
Lien : L'annexe sur les entités dans la norme XML Schema du W3C
Ce type permet de rendre annulable un type d'élément. Concrètement, ça permet de rendre une balise potentiellement vide, sans pour autant s'affranchir d'un type plus ou moins fort quand elle est remplie.
Cependant, la validation n'est pas effectuée quand la balise est simplement vide... C'est parce qu'il faut ajouter certaines spécificités pour le prendre en compte :
<
xsd
:
element
name
=
"myElement"
type
=
"myType"
nillable
=
"true"
/>
<root
xmlns
=
"http://www.exemple.com/XMLNameSpace"
xmlns
:
xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
>
<!-- etc... -->
<myElement
xsi
:
nil
=
"true"
/>
<!-- etc... -->
</root>
Cela permet de différencier une balise dont le contenu a été annulé (volontairement) d'une balise de valeur vide.
C'est assimilable à la différence entre un champ NULL et un champ contenant une chaîne vide pour les SGBD...
Il y a deux solutions, la première est d'utiliser nillable.
La seconde est de faire l'union du typage avec un type vide :
<
xsd
:
element
name
=
"myElement"
>
<
xsd
:
simpleType>
<
xsd
:
union
memberTypes
=
"myType"
>
<
xsd
:
simpleType>
<
xsd
:
restriction
base
=
"xsd:string"
>
<
xsd
:
enumeration
value
=
""
/>
</
xsd
:
restriction>
</
xsd
:
simpleType>
</
xsd
:
union>
</
xsd
:
simpleType>
</
xsd
:
element>
La méthode n'est pas aussi explicite que pour les éléments, cependant, il existe bien un moyen pour demander un choix entre plusieurs attributs :
Commencez par lister normalement tous les attributs que vous souhaitez proposer :
<
xsd
:
attribute
name
=
"a"
type
=
"xsd:string"
/>
<
xsd
:
attribute
name
=
"b"
type
=
"xsd:string"
/>
Ensuite, définissez une clé sur l'alternative entre les attributs que vous voulez rendre exclusifs :
<
xsd
:
key
name
=
"att"
>
<
xsd
:
selector
xpath
=
"."
/>
<
xsd
:
field
xpath
=
"@a|@b"
/>
</
xsd
:
key>
Voici un exemple complet :
<
xsd
:
element
name
=
"myElement"
>
<
xsd
:
complexType>
<
xsd
:
simpleContent>
<
xsd
:
extension
base
=
"xsd:string"
>
<
xsd
:
attribute
name
=
"a"
type
=
"xsd:string"
/>
<
xsd
:
attribute
name
=
"b"
type
=
"xsd:string"
/>
<
xsd
:
attribute
name
=
"c"
type
=
"xsd:string"
/>
</
xsd
:
extension>
</
xsd
:
simpleContent>
</
xsd
:
complexType>
<
xsd
:
key
name
=
"att"
>
<
xsd
:
selector
xpath
=
"."
/>
<
xsd
:
field
xpath
=
"@a|@b"
/>
</
xsd
:
key>
</
xsd
:
element>
Concrètement, cet attribut doit avoir un attribut c et en plus un attribut a ou bien un attribut b.
Le xsd:key indique que l'élément myElement est identifié par une clé dont la valeur est son attribut a ou sont attribut b.
Si les deux sont présent, même avec des valeurs identiques, cela créera automatiquement deux valeurs pour la clé : ce qui est une situation invalide.
Les clés (xsd:key) doivent avoir une valeur, il faut donc qu'un des attributs soit présent, pour palier à ceci, vous pouvez utiliser xsd:unique à sa place.
Le xsd:selector est là pour assurer que la contrainte d'unicité de la valeur ainsi définie ne s'étende à d'autres éléments... ainsi chaque balise myElement ne sera répertoriée que par rapport à elle-même. Aucun risque que la contrainte d'unicité ne pose problème.
Lien : La norme XSD sur les contraintes d'identité (clés, uniques, etc...)
Non, il n'existe aucun moyen de spécifier un ordre pour les attributs.
Il y a deux solutions, une avec xsd:all et une avec xsd:choice.
xsd:all implique que chacun des éléments/groupes d'éléments indiqués soient présents 1 ou 0 fois.
<xsd:all>
<xsd:element name="myElement-1" minOccurs="1" [...]/>
<xsd:element name="myElement-2" minOccurs="0" [...]/>
<xsd:element name="myElement-3" minOccurs="1" [...]/>
</xsd:all>
L'attribut minOccurs ne peut prendre que les valeurs 0 ou 1 et maxOccurs ne peuvent prendre que la valeur 1 (s'il est définie).
xsd:choice avec les attributs minOccurs à 0 et maxOccurs à unbounded :
<
xsd
:
choice
minOccurs
=
"0"
maxOccurs
=
"unbounded"
>
<
xsd
:
element
name
=
"tutu-1"
[...]/>
<
xsd
:
element
name
=
"tutu-2"
[...]/>
<
xsd
:
element
name
=
"tutu-3"
[...]/>
</
xsd
:
choice>
Mais on perd les occurrences de chaque éléments... Il n'y a pas, semble-t-il la possibilité de combiner les deux de manière triviale.
NON...
Il est impossible de faire quelque chose qui forcerait une structure dans ce style :
<a
b
=
"1"
c
=
"1"
>
<b>
a</b>
<c>
a</c>
</a>
<a
b
=
"2"
c
=
"1"
>
<b>
a</b>
<b>
a</b>
<c>
a</c>
</a>
<a
b
=
"1"
>
<b>
a</b>
</a>
Par exemple, faire l'équivalent de :
<
xsd
:
element
name
=
"myElement"
>
<
xsd
:
complexType>
<
xsd
:
choice>
<
xsd
:
sequence>
<
xsd
:
attribute
name
=
"a1"
type
=
"xsd:string"
use
=
"required"
/>
<
xsd
:
attribute
name
=
"a2"
type
=
"xsd:string"
use
=
"required"
/>
</
xsd
:
sequence>
<
xsd
:
sequence>
<
xsd
:
attribute
name
=
"b1"
type
=
"xsd:string"
use
=
"required"
/>
<
xsd
:
attribute
name
=
"b2"
type
=
"xsd:string"
use
=
"required"
/>
</
xsd
:
sequence>
</
xsd
:
choice>
</
xsd
:
complexType>
</
xsd
:
element
Dans ce cas là, oui, c'est possible... Il y a deux options :
La première consiste à créer des clés (comme pour Existe-t-il un équivalent de xsd:choice pour les attributs ?
) forçant les relations entre les attributs... Pour ce type de choix, il suffit de faire le produits cartésien des deux séquences (chaque élément de l'une avec chaque élément de l'autre).
<
xsd
:
element
name
=
"myElement"
>
<
xsd
:
complexType>
<
xsd
:
attribute
name
=
"a1"
type
=
"xsd:string"
/>
<
xsd
:
attribute
name
=
"a2"
type
=
"xsd:string"
/>
<
xsd
:
attribute
name
=
"b1"
type
=
"xsd:string"
/>
<
xsd
:
attribute
name
=
"b2"
type
=
"xsd:string"
/>
</
xsd
:
complexType>
<
xsd
:
key
name
=
"c-1-1"
>
<
xsd
:
selector
xpath
=
"."
/>
<
xsd
:
field
xpath
=
"@a1|@a1"
/>
</
xsd
:
key>
<
xsd
:
key
name
=
"c-1-2"
>
<
xsd
:
selector
xpath
=
"."
/>
<
xsd
:
field
xpath
=
"@a1|@b2"
/>
</
xsd
:
key>
<
xsd
:
key
name
=
"c-2-1"
>
<
xsd
:
selector
xpath
=
"."
/>
<
xsd
:
field
xpath
=
"@a2|@b1"
/>
</
xsd
:
key>
<
xsd
:
key
name
=
"c-2-2"
>
<
xsd
:
selector
xpath
=
"."
/>
<
xsd
:
field
xpath
=
"@a2|@b2"
/>
</
xsd
:
key>
</
xsd
:
element>
La seconde solution est d'utiliser un type abstrait possédant plusieurs alternatives au niveau des attributs (cf. Est-il possible de faire dépendre le contenu d'un élément de la valeur d'un attribut ?)
Dans le cas présent :
<
xsd
:
complexType
name
=
"myElementType"
abstract
=
"true"
/>
<
xsd
:
complexType
name
=
"myElementType-a"
>
<
xsd
:
complexContent
mixed
=
"true"
>
<
xsd
:
extension
base
=
"myElementType"
>
<
xsd
:
attribute
name
=
"a1"
type
=
"xsd:string"
/>
<
xsd
:
attribute
name
=
"a2"
type
=
"xsd:string"
/>
</
xsd
:
extension>
</
xsd
:
complexContent>
</
xsd
:
complexType>
<
xsd
:
complexType
name
=
"myElementType-b"
>
<
xsd
:
complexContent
mixed
=
"true"
>
<
xsd
:
extension
base
=
"myElementType"
>
<
xsd
:
attribute
name
=
"b1"
type
=
"xsd:string"
/>
<
xsd
:
attribute
name
=
"b2"
type
=
"xsd:string"
/>
</
xsd
:
extension>
</
xsd
:
complexContent>
</
xsd
:
complexType>
<
xsd
:
element
name
=
"myElement"
type
=
"myElementType"
/>
Lien : Existe-t-il un équivalent de xsd:choice pour les attributs ?
Lien : Est-il possible de faire dépendre le contenu d'un élément de la valeur d'un attribut ?
Ca dépend, dans le cas d'un nombre fini d'alternatives, oui, sinon non (exemple d'impossibilité : Est-il possible de faire dépendre le nombre d'élément [éventuellement d'un élément en particulier] dans les fils d'un éléments ?).
La solution repose sur les types abstraits et le XML NameSpace "XMLSchema-Instance" : on définie un type abstrait qui contient la structure commune de l'élément, puis on étend ce type pour chaque possibilité.
Ensuite, l'élément est déclaré comme étant du type abstrait. Un type abstrait ne pouvant être instancié, l'élément n'est pas validable si l'on ne spécifie pas un type concret, donc on va utiliser l'attribut xsi:type pour précisé un des types étendus.
La validation sera effective car l'élément respectera le type abstrait (puisqu'il sera d'un type étendu) et il respectera également le type étendu. C'est l'attribut xsi:type qui spécifie le type utilisé (et donc le contenu et les attributs à insérer).
Il est impossible de reporter cette responsabilité sur un autre attribut !
Exemple :
<
xsd
:
complexType
name
=
"myElementType"
abstract
=
"true"
/>
<
xsd
:
complexType
name
=
"myElementType-1"
>
<
xsd
:
complexContent
mixed
=
"true"
>
<
xsd
:
extension
base
=
"myElementType"
>
<
xsd
:
attribute
name
=
"att1"
type
=
"xsd:string"
/>
<
xsd
:
element
name
=
"elem1"
/>
</
xsd
:
extension>
</
xsd
:
complexContent>
</
xsd
:
complexType>
<
xsd
:
complexType
name
=
"myElementType-2"
>
<
xsd
:
complexContent
mixed
=
"true"
>
<
xsd
:
extension
base
=
"myElementType"
>
<
xsd
:
attribute
name
=
"att2"
type
=
"xsd:string"
/>
<
xsd
:
choice>
<
xsd
:
element
name
=
"elem2"
/>
<
xsd
:
element
name
=
"elem3"
/>
</
xsd
:
choice>
</
xsd
:
extension>
</
xsd
:
complexContent>
</
xsd
:
complexType>
<
xsd
:
element
name
=
"myElement"
type
=
"myElementType"
/>
<root
xmlns
:
xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns
=
"http://www.exemple.com/XMLNameSpace"
>
<!-- etc... -->
<myElement
xsi
:
type
=
"myElementType-1"
att1
=
"first"
>
<elem1>
2006-12-25</elem1>
</myElement>
<!-- etc... -->
<myElement
xsi
:
type
=
"myElementType-2"
att2
=
"second"
>
<elem3>
boat</elem3>
</myElement>
<!-- etc... -->
</root>
Oui, il suffit d'utiliser le type anyType, il accepte toute formation (attributs et contenu).
<
xsd
:
element
name
=
"myElement"
type
=
"anyType"
/>