1. A cosa serve la validazione XML
XML è un formato molto flessibile, a volte anche troppo. A differenza di dati fortemente tipizzati, XML "tollera" errori, e se dimentichi di chiudere un tag, o qualcuno mette il nome sbagliato di un attributo, il programma può dare un errore durante il parsing… o non accorgersi del problema, il che è peggio.
La validazione tramite XSD (XML Schema Definition) è un modo per assicurarsi che il tuo file XML rispetti un contratto predefinito: come si chiamano i tag, in che ordine vanno, di che tipo sono, se sono obbligatori e quante occorrenze sono ammesse. È come il controllo passaporti per i tuoi dati — lo schema dice: "Non si entra senza il campo richiesto o se il campo non ha la lunghezza giusta!"
La validazione è importante nei sistemi enterprise, nello scambio di dati tra sistemi diversi, negli API — ovunque sia indesiderato accettare "silenziosamente" strutture malformate.
XSD (XML Schema Definition) è un documento XML separato che formalizza la struttura di un altro XML. Nell'XSD descrivi: quali tag sono ammessi, quali sono obbligatori, i tipi di attributi o di elementi figli, pattern per le stringhe, vincoli per i numeri, persino i valori possibili (via restrizioni e enumerazioni).
| XML | XSD (descrizione della struttura) |
|---|---|
|
|
|
|
XSD è concettualmente simile a JSON Schema nel mondo JSON.
2. Esempio di XSD e XML correlato
Esempio XML
<person age="23">
<name>Ivan</name>
<email>ivan@example.com</email>
</person>
Esempio XSD
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="person">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="email" type="xs:string" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="age" type="xs:positiveInteger" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>
Che cosa descrive questo schema:
- L'elemento root è <person>.
- Dentro <person> devono esserci gli elementi <name> (obbligatorio) e <email> (opzionale).
- Il <person> deve avere l'attributo age con un valore intero positivo.
3. Validare XML con XSD in .NET
In .NET il classico è usare gli namespace System.Xml e System.Xml.Schema.
Flusso di lavoro:
- Caricare il file XML
- Caricare lo schema XSD
- "Attaccare" lo schema alla validazione dell'XML
- Avviare il processo di validazione e gestire eventuali errori
Ecco un esempio base:
using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
// 1. Handler per gli errori di validazione
void ValidationCallBack(object? sender, ValidationEventArgs e)
{
Console.WriteLine($"Errore di validazione: {e.Message}");
}
string xmlPath = "person.xml";
string xsdPath = "person.xsd";
// 2. Carichiamo lo schema
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("", xsdPath);
XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas = schemas;
settings.ValidationType = ValidationType.Schema;
settings.ValidationEventHandler += ValidationCallBack;
// 3. Apriamo l'XML con le impostazioni
using XmlReader reader = XmlReader.Create(xmlPath, settings);
while (reader.Read())
{
// Semplicemente scorriamo il documento - la validazione avviene "on the fly"
}
Console.WriteLine("Validazione completata!");
Note:
- Tutti gli errori di validazione saranno intercettati nel callback ValidationCallBack.
- Se non ci sono errori — il documento rispetta lo schema (ValidationType.Schema).
- Se ci sono discrepanze (manca age, email non valida, campo extra ecc.) — compariranno nella console.
Tipi diversi di errori e feedback
La validazione tramite XSD può "lamentarsi" per vari motivi. Ecco gli scenari più comuni e esempi di errori:
- Manca un elemento obbligatorio (di default minOccurs="1")
- Tag extra non descritto nello XSD
- Attributo di tipo sbagliato (age="abc" invece di un numero)
- Stringhe che non rispettano il pattern (definito con <xs:pattern>)
Errore tipico:
Errore di validazione: L'elemento 'age' con contenuto testuale 'abc' non è valido. Era atteso un valore di tipo 'xs:positiveInteger'.
4. XSD più complicati: tipi, enumerazioni, pattern
XSD è praticamente un linguaggio per descrivere dati validi. Ecco alcuni esempi avanzati:
Enumerazione di valori ammessi
<xs:element name="gender">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="male"/>
<xs:enumeration value="female"/>
<xs:enumeration value="diverse"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
Limitazione della lunghezza della stringa
<xs:element name="code">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:length value="8"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
Pattern per email (semplificato)
<xs:element name="email">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:pattern value="\w+@\w+\.\w+"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
Puoi creare tipi personalizzati, ereditarli, usare elementi annidati — praticamente come in OOP!
5. Validazione di un documento complesso
Immaginiamo che la nostra app didattica ora esporti una lista di studenti in XML. Aggiungiamo del codice!
Esempio XML
<students>
<student id="1">
<name>Elena</name>
<grade>5</grade>
</student>
<student id="2">
<name>Alexey</name>
<grade>4</grade>
</student>
</students>
Schema XSD
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="students">
<xs:complexType>
<xs:sequence>
<xs:element name="student" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="grade">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="5"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
<xs:attribute name="id" type="xs:integer" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Validazione nel codice (stessi approcci):
// Percorsi ai file
string xmlPath = "students.xml";
string xsdPath = "students.xsd";
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("", xsdPath);
XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas = schemas;
settings.ValidationType = ValidationType.Schema;
settings.ValidationEventHandler += ValidationCallBack;
using XmlReader reader = XmlReader.Create(xmlPath, settings);
while (reader.Read()) { /* tutto come prima */ }
6. Sfumature utili
Come specificare lo schema direttamente nell'XML (xsi:schemaLocation)
In pratica si trovano spesso file XML che dichiarano nell'elemento root gli attributi xsi:schemaLocation o xsi:noNamespaceSchemaLocation:
<students xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="students.xsd">
...
</students>
Questo non valida automaticamente il file, ma aiuta alcuni validator ed editor a trovare lo schema per il controllo. Nella validazione .NET non è obbligatorio, ma è formalmente corretto.
Validazione "on the fly" e in memoria — con XDocument
Se lavori con LINQ to XML (XDocument), puoi anche validare il documento XML in memoria, senza usare file:
using System.Xml.Linq;
using System.Xml.Schema;
// Caricamento dello schema
XmlSchemaSet schema = new XmlSchemaSet();
schema.Add("", "students.xsd");
// Caricamento dell'XML in memoria
XDocument doc = XDocument.Load("students.xml");
// Validazione
doc.Validate(schema,
(o, e) => Console.WriteLine($"Errore: {e.Message}"),
true // Controllare i warning (spesso ridondante)
);
Questo approccio è comodo se crei o modifichi XML programmaticamente e vuoi assicurarti di non generare un altro mostro XML che violi lo schema.
7. Errori tipici nella validazione XML con XSD
Errore n.1: hai dimenticato di aggiungere lo schema o il percorso allo XSD è sbagliato.
Di conseguenza non viene eseguita alcuna validazione e il file XML passa "attraverso la guardia", anche se contiene errori. Spesso il percorso è relativo e l'app cerca il file in una cartella inaspettata. Per i test è meglio usare un percorso assoluto o mettere lo schema accanto all'eseguibile.
Errore n.2: gli namespace non coincidono.
Se lo schema usa uno namespace, devi passarne il valore come primo argomento quando aggiungi lo schema a XmlSchemaSet.Add. Altrimenti la validazione fallirà anche se la struttura XML è corretta. Se non ci sono namespace — passa una stringa vuota.
Errore n.3: ordine degli elementi non corrispondente.
Se nello schema è definito un <xs:sequence>, allora l'ordine degli elementi conta. Un XML con gli elementi giusti ma in ordine sbagliato sarà considerato invalido.
Errore n.4: nell'XML sono indicati più namespace.
Se il documento usa più di uno namespace, questo può causare comportamenti inaspettati nella validazione. Supportare namespace multipli richiede attenzione e configurazione precisa degli schema.
Errore n.5: non raccogliere e non salvare gli errori.
Stampare gli errori in console può andare bene per il debug, ma non per un'app in produzione. È meglio raccogliere gli errori in una lista e presentarli all'utente in modo fruibile — soprattutto quando si validano molti file (ad esempio su un web server).
GO TO FULL VERSION