Se hai mai integrato un'API XML aziendale e ricevuto un rifiuto criptico con "element 'Quantity' is not valid in this context", hai già incontrato XSD — anche se non sapevi come si chiamasse. XML Schema Definition (XSD) è il linguaggio che definisce esattamente come deve apparire un XML valido: quali elementi sono obbligatori, quali tipi di dati contengono, quante volte possono comparire e quali valori sono consentiti. Questa guida spiega come scrivere schemi, validare contro di essi e gestire gli errori che inevitabilmente incontrerai.
XSD è definito dalla specifica W3C XML Schema, pubblicata per la prima volta nel 2001. La XML Schema Part 2: Datatypes raccomanda il sistema di tipi built-in. È verboso e un po' arcano da scrivere a mano, ma estremamente preciso — esattamente ciò di cui hai bisogno quando scambi dati tra sistemi che non tollerano ambiguità.
Perché validare XML?
- Intercetta gli errori presto. La validazione al boundary dell'API significa che un campo obbligatorio mancante fallisce immediatamente con un errore chiaro — non 3 passi dopo quando il tuo insert nel database lancia una violazione di constraint.
- Documenta il contratto. Uno schema XSD è documentazione eseguibile. A differenza di un documento Word che diventa obsoleto, uno schema è sempre accurato perché il sistema lo applica.
- Interoperabilità. Nelle integrazioni B2B — fatturazione, gestione ordini, sanità — entrambe le parti validano contro uno schema pubblicato condiviso. Se passa la validazione, entrambe le parti possono elaborarlo.
- Sicurezza. La validazione rifiuta input malformati prima che raggiungano la business logic, riducendo la superficie di attacco per gli attacchi di XML injection.
Un esempio completo di schema XSD
Costruiamo uno schema per un catalogo prodotti. Questo copre le funzionalità XSD più comunemente usate — tipi semplici, tipi complessi, sequenze, attributi, cardinalità e vincoli sul tipo di dato:
<?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>Molti concetti da assimilare. Analizziamo quelli chiave prima di mostrare la validazione in azione.
Concetti chiave di XSD spiegati
- xs:element. Dichiara un elemento.
minOccursemaxOccurscontrollano la cardinalità. Il valore predefinito per entrambi è 1. UsamaxOccurs="unbounded"per ripetizioni illimitate. - xs:complexType. Un elemento che contiene elementi figli o ha attributi. Gli elementi semplici (solo testo) usano
xs:simpleTypeo direttamente un tipo built-in XSD. - xs:sequence. Gli elementi figli devono apparire nell'ordine definito. L'alternativa è
xs:all(qualsiasi ordine, al massimo una volta ciascuno) oxs:choice(esattamente uno degli elementi elencati). - xs:attribute use="required". Rende l'attributo obbligatorio.
use="optional"(predefinito) permette che sia assente. Aggiungidefault="value"per un valore predefinito quando assente. - xs:restriction. Vincola un tipo base. Facet comuni:
xs:pattern(regex),xs:enumeration(valori consentiti),xs:minInclusive/xs:maxInclusive(limiti numerici),xs:minLength/xs:maxLength(lunghezza stringa). - xs:simpleContent + xs:extension. Il modo per aggiungere attributi a un elemento che ha anche contenuto testuale — come usato in
PriceTypesopra dove<price currency="USD">149.99</price>ha sia testo che un attributo.
Tipi di dati XSD built-in che userai davvero
xs:string— qualsiasi contenuto testualexs:integer— numeri interi (positivi, negativi o zero)xs:nonNegativeInteger— numeri interi ≥ 0 (ottimo per quantità e contatori)xs:decimal— decimale a precisione arbitraria (ottimo per prezzi)xs:boolean—trueofalse(accetta anche1e0)xs:date— data ISO 8601:2024-01-15xs:dateTime— datetime ISO 8601:2024-01-15T09:30:00Zxs:anyURI— un URI/URLxs:base64Binary— dati binari codificati in Base64
Validare XML contro uno XSD in Python (lxml)
Il modulo standard di Python xml.etree.ElementTree non supporta la validazione XSD.
Per questo serve lxml.
Vale la dipendenza — i messaggi di validazione di lxml sono dettagliati e puntano alla riga esatta
che causa il problema:
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 > 0Validare in Java — JAXP
Java dispone di validazione XSD built-in tramite le API di validazione JAXP (nessuna libreria di terze parti necessaria). Questo è il pattern usato nelle applicazioni Java enterprise e nel processing XML con 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
Se hai già usato JSON Schema, XSD ti sembrerà familiare nello scopo ma molto diverso nella sintassi. Un rapido confronto:
- Sintassi. XSD è XML; JSON Schema è JSON. XSD è più verboso ma si integra naturalmente nelle toolchain XML.
- Maturità. XSD 1.0 esiste dal 2001 — decenni di strumenti, validatori e supporto delle librerie. JSON Schema è in evoluzione dal 2009 e solo negli ultimi anni ha raggiunto una bozza stabile.
- Sistema di tipi. XSD ha un sistema di tipi built-in più ricco:
xs:date,xs:decimal,xs:anyURIsono built-in. JSON Schema si affida ad annotazioni di formato per date e URI, che i validatori possono o meno applicare. - Supporto namespace. XSD ha supporto nativo per i namespace XML. JSON Schema non ha un concetto equivalente.
- Quando usare cosa. Se lavori in un ecosistema XML, usa XSD. Se lavori in un ecosistema JSON, usa JSON Schema. Non mescolarli.
Errori di validazione comuni e come correggerli
- "Element X is not expected." L'elemento appare fuori ordine in una
xs:sequence, o non è definito nello schema. Controlla il nome dell'elemento e la sua posizione rispetto ai fratelli. - "The value Y of attribute Z is not valid." Il valore dell'attributo non corrisponde al suo tipo o enumerazione. Comune per i campi di stato e i codici valuta con errori di battitura.
- "Missing child element(s)." Un elemento figlio obbligatorio (minOccurs > 0) è assente. Controlla lo schema per vedere quali elementi sono obbligatori sotto l'elemento padre.
- "Not a valid value of the atomic type." Una restrizione di tipo semplice non è soddisfatta — pattern, intervallo o enumerazione. Controlla lo schema per la
xs:restrictionsu quel tipo. - "Content model is not determinist." Schema ambiguo — il validatore non riesce a determinare quale ramo applicare. Di solito causato da due opzioni con lo stesso nome tag in una
xs:choice.
Strumenti correlati
Lavori con schemi XML? Questi strumenti ti saranno utili: XML Validator per verifiche rapide della correttezza formale, XML Formatter per rendere leggibile l'XML denso prima del debug, XML Schema Generator per generare automaticamente un XSD da un documento XML di esempio, e XML to JSON quando preferisci lavorare con JSON Schema.
Conclusione
XSD è verboso, ma è lo strumento giusto per definire contratti XML rigorosi in contesti enterprise
e B2B. I pattern chiave da ricordare: usa xs:sequence con
minOccurs/maxOccurs per controllare la struttura, usa xs:restriction
con xs:enumeration e xs:pattern per i vincoli sui valori, e usa
lxml in Python per la validazione con messaggi di errore chiari. Una volta che hai uno schema
funzionante, diventa la fonte unica di verità a cui entrambe le parti di un'integrazione possono fare
riferimento — il che risparmia molti cicli di debug.