Si vous avez intégré une API XML d'entreprise et reçu un rejet cryptique du type « l'élément 'Quantity' n'est pas valide dans ce contexte », vous avez déjà rencontré XSD — même si vous ne connaissiez pas ce nom. XML Schema Definition (XSD) est le langage qui définit exactement à quoi ressemble un XML valide : quels éléments sont obligatoires, quels types de données ils contiennent, combien de fois ils peuvent apparaître, et quelles valeurs sont autorisées. Ce guide explique comment écrire des schémas, valider des documents XML et gérer les erreurs que vous rencontrerez inévitablement.
XSD est défini par la spécification XML Schema du W3C, publiée pour la première fois en 2001. La recommandation XML Schema Part 2: Datatypes définit le système de types intégrés. C'est verbeux et un peu ésotérique à écrire à la main, mais d'une précision extrême — ce dont vous avez exactement besoin pour échanger des données entre systèmes qui ne tolèrent pas l'ambiguïté.
Pourquoi valider le XML ?
- Détecter les erreurs tôt. La validation à la frontière de l'API signifie qu'un champ obligatoire manquant échoue immédiatement avec un message clair — et non 3 étapes plus tard quand votre INSERT en base de données génère une violation de contrainte.
- Documenter le contrat. Un schéma XSD est une documentation exécutable. Contrairement à un document Word qui devient obsolète, un schéma est toujours à jour car le système l'applique.
- Interopérabilité. Dans les intégrations B2B — facturation, gestion des commandes, santé — les deux parties valident contre un schéma publié commun. Si ça valide, les deux côtés peuvent le traiter.
- Sécurité. La validation rejette les entrées malformées avant qu'elles n'atteignent la logique métier, réduisant la surface d'attaque contre les injections XML.
Un exemple complet de schéma XSD
Construisons un schéma pour un catalogue de produits. Cet exemple couvre les fonctionnalités XSD les plus courantes — types simples, types complexes, séquences, attributs, cardinalité et contraintes de types de données :
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- Root element -->
<xs:element name="catalog">
<xs:complexType>
<xs:sequence>
<!-- One or more product elements -->
<xs:element name="product" type="ProductType" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="version" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
<!-- Product complex type -->
<xs:complexType name="ProductType">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="description" type="xs:string" minOccurs="0"/>
<xs:element name="price" type="PriceType"/>
<xs:element name="stock" type="xs:nonNegativeInteger"/>
<xs:element name="categories" type="CategoriesType"/>
</xs:sequence>
<xs:attribute name="id" type="ProductIdType" use="required"/>
<xs:attribute name="status" type="ProductStatusType" use="optional" default="active"/>
</xs:complexType>
<!-- Price with currency attribute -->
<xs:complexType name="PriceType">
<xs:simpleContent>
<xs:extension base="xs:decimal">
<xs:attribute name="currency" type="CurrencyCodeType" use="required"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!-- Categories — zero or more category strings -->
<xs:complexType name="CategoriesType">
<xs:sequence>
<xs:element name="category" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<!-- Product ID: alphanumeric, starts with P, 4-10 chars -->
<xs:simpleType name="ProductIdType">
<xs:restriction base="xs:string">
<xs:pattern value="P[A-Z0-9]{3,9}"/>
</xs:restriction>
</xs:simpleType>
<!-- Allowed product statuses -->
<xs:simpleType name="ProductStatusType">
<xs:restriction base="xs:string">
<xs:enumeration value="active"/>
<xs:enumeration value="discontinued"/>
<xs:enumeration value="out_of_stock"/>
</xs:restriction>
</xs:simpleType>
<!-- ISO 4217 currency codes — a subset -->
<xs:simpleType name="CurrencyCodeType">
<xs:restriction base="xs:string">
<xs:enumeration value="USD"/>
<xs:enumeration value="EUR"/>
<xs:enumeration value="GBP"/>
<xs:enumeration value="JPY"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>Beaucoup à assimiler. Passons en revue les concepts clés avant de voir la validation en action.
Concepts XSD clés expliqués
- xs:element. Déclare un élément.
minOccursetmaxOccurscontrôlent la cardinalité. La valeur par défaut des deux est 1. UtilisezmaxOccurs="unbounded"pour une répétition illimitée. - xs:complexType. Un élément qui contient des éléments enfants ou possède des attributs. Les éléments simples (texte uniquement) utilisent
xs:simpleTypeou un type intégré XSD directement. - xs:sequence. Les éléments enfants doivent apparaître dans l'ordre défini. L'alternative est
xs:all(ordre quelconque, chacun au plus une fois) ouxs:choice(exactement un des éléments listés). - xs:attribute use="required". Rend l'attribut obligatoire.
use="optional"(par défaut) permet son absence. Ajoutezdefault="valeur"pour une valeur par défaut en cas d'absence. - xs:restriction. Contraint un type de base. Facettes courantes :
xs:pattern(regex),xs:enumeration(valeurs autorisées),xs:minInclusive/xs:maxInclusive(bornes numériques),xs:minLength/xs:maxLength(longueur de chaîne). - xs:simpleContent + xs:extension. La manière d'ajouter des attributs à un élément qui a aussi du contenu texte — comme dans le
PriceTypeci-dessus où<price currency="USD">149.99</price>a à la fois du texte et un attribut.
Types de données XSD intégrés que vous utiliserez vraiment
xs:string— tout contenu textuelxs:integer— nombres entiers (positifs, négatifs ou zéro)xs:nonNegativeInteger— entiers ≥ 0 (idéal pour les quantités)xs:decimal— décimal à précision arbitraire (idéal pour les prix)xs:boolean—trueoufalse(accepte aussi1et0)xs:date— date ISO 8601 :2024-01-15xs:dateTime— datetime ISO 8601 :2024-01-15T09:30:00Zxs:anyURI— un URI/URLxs:base64Binary— données binaires encodées en Base64
Valider du XML contre un XSD en Python (lxml)
Le module standard Python xml.etree.ElementTree ne supporte pas la validation XSD.
Il vous faut lxml pour ça.
La dépendance en vaut la peine — les messages de validation de lxml sont détaillés et pointent exactement
vers la ligne qui pose problème :
pip install lxmlfrom lxml import etree
# Load the schema
with open('catalog.xsd', 'rb') as f:
schema_doc = etree.parse(f)
schema = etree.XMLSchema(schema_doc)
# Valid XML
valid_xml = """<?xml version="1.0"?>
<catalog version="1.0">
<product id="P0012" status="active">
<name>Mechanical Keyboard</name>
<price currency="USD">189.00</price>
<stock>42</stock>
<categories>
<category>Electronics</category>
<category>Peripherals</category>
</categories>
</product>
</catalog>"""
xml_doc = etree.fromstring(valid_xml.encode())
if schema.validate(xml_doc):
print("Valid!")
else:
for error in schema.error_log:
print(f"Error at line {error.line}: {error.message}")
# Invalid XML — missing required 'stock', bad product ID format
invalid_xml = """<?xml version="1.0"?>
<catalog version="1.0">
<product id="BADID">
<name>Test Product</name>
<price currency="USD">10.00</price>
<categories/>
</product>
</catalog>"""
invalid_doc = etree.fromstring(invalid_xml.encode())
schema.validate(invalid_doc)
for error in schema.error_log:
print(f"Line {error.line}: {error.message}")
# Line 3: Element 'product', attribute 'id': 'BADID' is not a valid value of the atomic type 'ProductIdType'.
# Line 7: Element 'categories': Missing child element(s). Expected is ( category ). ← if minOccurs > 0Validation en Java — JAXP
Java dispose d'une validation XSD intégrée via l' API de validation JAXP (aucune bibliothèque tierce nécessaire). C'est le schéma utilisé dans les applications Java d'entreprise et le traitement XML Spring Boot :
import javax.xml.XMLConstants;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import javax.xml.transform.stream.StreamSource;
import java.io.File;
import org.xml.sax.SAXException;
import java.io.IOException;
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(new File("catalog.xsd"));
Validator validator = schema.newValidator();
try {
validator.validate(new StreamSource(new File("catalog.xml")));
System.out.println("Valid!");
} catch (SAXException e) {
System.out.println("Validation error: " + e.getMessage());
} catch (IOException e) {
System.out.println("IO error: " + e.getMessage());
}XML Schema vs JSON Schema
Si vous avez utilisé JSON Schema, XSD vous paraîtra familier dans son objectif mais très différent dans sa syntaxe. Une comparaison rapide :
- Syntaxe. XSD est du XML ; JSON Schema est du JSON. XSD est plus verbeux mais s'intègre naturellement dans les chaînes d'outils XML.
- Maturité. XSD 1.0 existe depuis 2001 — des décennies d'outillage, de validateurs et de support de bibliothèques. JSON Schema évolue depuis 2009 et n'a atteint un brouillon stable que récemment.
- Système de types. XSD dispose d'un système de types intégrés plus riche :
xs:date,xs:decimal,xs:anyURIsont intégrés. JSON Schema s'appuie sur des annotations de format pour les dates et les URI, que les validateurs peuvent ou non appliquer. - Support des espaces de noms. XSD dispose d'un support natif des espaces de noms XML. JSON Schema n'a pas de concept équivalent.
- Quand utiliser lequel. Si vous travaillez dans un écosystème XML, utilisez XSD. Si vous travaillez dans un écosystème JSON, utilisez JSON Schema. Ne les mélangez pas.
Erreurs de validation courantes et comment les corriger
- « L'élément X n'est pas attendu. » L'élément apparaît dans le mauvais ordre dans une
xs:sequence, ou n'est pas défini dans le schéma du tout. Vérifiez le nom de l'élément et sa position par rapport à ses frères. - « La valeur Y de l'attribut Z n'est pas valide. » La valeur de l'attribut ne correspond pas à son type ou à son énumération. Fréquent pour les champs de statut et les codes de devise avec des fautes de frappe.
- « Élément(s) enfant manquant(s). » Un élément enfant obligatoire (minOccurs > 0) est absent. Vérifiez dans le schéma quels éléments sont obligatoires sous le parent.
- « Pas une valeur valide du type atomique. » Une restriction de type simple a échoué — pattern, plage ou énumération. Vérifiez la
xs:restrictionsur ce type dans le schéma. - « Le modèle de contenu n'est pas déterministe. » Schéma ambigu — le validateur ne peut pas déterminer quelle branche s'applique. Généralement causé par deux options avec le même nom de balise dans un
xs:choice.
Outils associés
Vous travaillez avec des schémas XML ? Ces outils vous aideront : Validateur XML pour des vérifications rapides de la bonne formation, Formateur XML pour rendre un XML dense lisible avant le débogage, Générateur de schéma XML pour générer automatiquement un XSD à partir d'un exemple de document XML, et XML vers JSON quand vous préférez travailler avec JSON Schema.
Conclusion
XSD est verbeux, mais c'est le bon outil pour définir des contrats XML stricts dans les contextes
d'entreprise et B2B. Les schémas clés à retenir : utilisez xs:sequence avec
minOccurs/maxOccurs pour contrôler la structure, utilisez xs:restriction
avec xs:enumeration et xs:pattern pour les contraintes de valeur, et utilisez
lxml en Python pour la validation avec des messages d'erreur clairs. Une fois que vous avez un
schéma fonctionnel, il devient la source de vérité unique que les deux parties d'une intégration peuvent
consulter — ce qui évite beaucoup d'allers-retours de débogage.