Nell'articolo «Uno sguardo ad XML» abbiamo avuto modo di esplorare i principi di base dell'XML e, in particolare, avevamo parlato del ruolo dei Document Type Definition (DTD) nella definizione della struttura di un documento.
Infatti, anche se XML ci consente la massima libertà nella definizione dei tag, abbiamo la necessità di imporre dei vincoli alla struttura di un documento per evitare l'insorgere incontrollato di tag e per consentire un'elaborazione accurata da parte di determinati programmi (per esempio, processori XSLT ed altri programmi di trasformazione). In pratica quello che facciamo con i DTD è definire la grammatica di un linguaggio a marcatori basato su XML utilizzabile per una specifica classe di documenti.
Tuttavia i DTD presentano alcuni aspetti che non soddisfano pienamente le attese degli sviluppatori. Ad esempio, secondo i DTD il contenuto dei tag ` sempre testo (#PCDATA); non è prevista la possibilità di definire tipi di dato e pertanto non è possibile ottenere un controllo accurato sul contenuto dei tag e sul valore degli attributi. Non c'è possibilità di comporre documenti XML che facciano riferimento a DTD diversi. Come se non bastasse, la sintassi utilizzata per definire i DTD ha poco a che vedere con XML. A prima vista quest'ultimo aspetto può essere considerato di poco conto, ma ha invece la sua importanza se consideriamo che in linea di principio non possiamo riutilizzare gli stessi strumenti che usiamo per XML quando lavoriamo con un DTD.
A questi problemi cercano di dare una soluzione gli XML Schema.
XML Schema
Uno XML Schema è un documento XML che utilizza un insieme di tag speciali per definire la struttura di un documento XML. Da questa definizione emerge subito una novità interessante: viene utilizzato un documento XML per validare un altro documento XML!
Il vincolo che dobbiamo rispettare nella creazione di uno schema è l'uso dei tag definiti dall'XML Schema Language definito dal W3C nei documenti www.w3.org/TR/xmlschema-0, www.w3.org/TR/xmlschema-1 e www.w3.org/TR/xmlschema-2. In particolare uno XML Schema ha la seguente struttura generale:
<?xml version"1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
... Definizione della grammatica ...
</xs:schema>
L'elemento root del documento è rappresentato dal tag <xs:schema>, il quale specifica tramite l'attributo xmlns che in questo documento saranno utilizzati dei tag definiti da uno specifico standard del W3C.
Tipi di dato
Una delle principali novità introdotte dagli XML Schema rispetto ai DTD è la possibilità non solo di definire il tipo di dato di un elemento, ma anche di poter personalizzare un tipo di dato. Esistono due categorie di tipi di dato: semplici e complessi.
I tipi di dato semplici sono relativi a quegli elementi che non possono contenere altri elementi e non prevedono attributi. Sono previsti numerosi tipi di dato predefiniti; a titolo d'esempio, possiamo imporre il vincolo che un elemento contenga informazioni di tipo stringa, intero, booleano, data, ecc.
È possibile definire tipi semplici personalizzati derivandoli da quelli predefiniti. Ad esempio, possiamo definire un tipo di dato come restrizione del tipo stringa, vincolando i valori ad uno specifico insieme di stringhe o ad un pattern individuato da un'espressione regolare.
I tipi di dato complessi si riferiscono alla definizione degli elementi con attributi e che possono contenere altri elementi. La definizione del tipo complesso consiste generalmente nella definizione della struttura prevista dall'elemento. Se l'elemento può contenere altri elementi possiamo definire l'insieme degli elementi che possono stare al suo interno come sequenza, come insieme di valori alternativi o come gruppo.
Un esempio
Ma vediamo un po' più in concreto come è fatto uno XML Schema. Riprendiamo l'esempio dell'articolo citato all'inizio relativo alla definizione in XML di una ricetta di cucina:
<?xml version="1.0" ?>
<!-Esempio di ricetta in XML -->
<ricetta>
<pietanza nome="Pasta al burro" />
<ingredienti>
<ingrediente um="grammi" qta="500">Spaghetti</ingrediente>
<ingrediente um="litri" qta="2,5">Acqua</ingrediente>
<ingrediente um="grammi" qta="10">Sale</ingrediente>
<ingrediente um="grammi" qta="100">Burro</ingrediente>
<ingrediente um="grammi" qta="50">
Formaggio grattugiato
</ingrediente>
</ingredienti>
<procedimento>
Portare ad ebollizione l'acqua salata ed immergere gli
spaghetti girandoli di tanto in tanto con una forchetta.
Dividere il burro nei piatti da servire a tavola. Dopo
circa 7-8 minuti scolare gli spaghetti e distribuirli nei
piatti con il burro. Aggiungere il formaggio grattugiato
e servire in tavola.
</procedimento>
</ricetta>
Un possibile schema che definisce la struttura di questo documento è il seguente:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="ricetta">
<xs:complexType>
<xs:sequence>
<xs:element name="pietanza" type="xs:string"/>
<xs:element name="ingredienti">
<xs:complexType>
<xs:sequence>
<xs:element name="ingrediente" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="um" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="grammi"/>
<xs:enumeration value="etti"/>
<xs:enumeration value="chili"/>
<xs:enumeration value="litri"/>
<xs:enumeration value="cucchiai"/>
<xs:enumeration value="pizzichi"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="qta" type="xs:integer" use="required"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="procedimento" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Analizziamo il suo contenuto per scoprire le caratteristiche principali degli XML Schema.
In esso definiamo tramite il tag <xs:element> gli elementi del nostro documento. In particolare iniziamo con l'elemento root ricetta. Questo elemento risulta di tipo complesso, dal momento che contiene altri elementi. Ciò viene specificato tramite il tag <xs:complexType>, che definisce la sequenza (<xs:sequence>) degli elementi che si possono trovare al suo interno. L'elemento pietanza viene definito di tipo stringa, mentre l'elemento ingredienti è un elemento di tipo complesso costituito da una sequenza di uno o più elementi ingrediente. Quest'ultimo elemento è il più complesso del nostro schema. Infatti esso è definito come un elemento che non contiene altri elementi (<xs:simpleContent>) ma contiene informazioni di tipo stringa. Esso prevede anche due attributi definiti tramite i tag <xs:attribute>. L'attributo um è obbligatorio (use="required") ed i valori consentiti sono basati su una restrizione del tipo stringa (<xs:restriction>); in particolare la restrizione è basata sull'enumerazione delle possibili stringhe valide e non sono consentite stringhe diverse da quelle specificate. L'attributo qta, anch'esso obbligatorio, può contenere soltanto valori di tipo intero.
Infine l'ultimo elemento della sequenzaè l'elemento procedimento che può cantenere informazioni di tipo stringa.
Il documento e lo schema
Una volta definito lo schema per i nostri documenti XML, non ci resta che indicare all'interno del documento l'XML Schema di riferimento per consentire ai parser verificarne la validità. Il riferimento allo schema puòsere fatto aggiungendo all'elemento root del documento XML due attributi, come nel seguente esempio:
<ricetta xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ricette.xsd">
L'attributo xmlns:xsi indica la modalità con cui si indicherà il riferimento all'XML Schema, mentre l'attributo xsi:noNamespaceSchemaLocation indica il nome e l'eventuale percorso del file contenente l'XML Schema di riferimento.
Caratteristiche avanzate
Nell'esempio illustrato in questo articolo abbiamo visto gli elementi di base della creazione di XML Schema. Questa tecnologia prevede numerose altre caratteristiche che la rendono uno strumento flessibile e potente per descrivere le regole di validità di un documento XML.
Ad esempio, è possibile dichiarare tipi di dato personalizzati e fare riferimento a tali dichiarazioni quando si definisce un elemento, in modo analogo a come avviene per la definizione di tipi nei linguaggi di programmazione. Questo consente di rendere più leggibile lo schema e di concentrare in un unico punto la definizione di un tipo utilizzato diverse volte.
È possibile comporre schemi includendo o importando schemi diversi ed è possibile comporre documenti XML utilizzando tag definiti in schemi diversi. Ad esempio, possiamo integrare i nostri documenti XML che descrivono ricette di cucina con l'introduzione di nuovi elementi che definiscono gli utensili che servono per eseguire ciascuna ricetta. Supponendo che tali elementi siano definiti in un apposito XML Schema, possiamo combinare i tag derivanti dai due schemi in un unico documento XML, sfruttando un meccanismo noto come namespace.
Considerando quanto abbiamo visto ed accennato in questo articolo, risultano evidenti i vantaggi offerti dagli XML Schema nei confronti dei DTD. Tuttavia, il prezzo da pagare per un più accurato controllo offerto da questa tecnologia è la loro maggiore complessità rispetto ai loro predecessori.
Andrea Chiarelli a.chiarelli@manthys.it) si occupa di progettazione e sviluppo di applicazioni Web e di formazione professionale presso Manthys (www.manthys.it), società di formazione e consulenza informatica di cui è titolare. Collabora con diverse riviste di settore sia italiane (Computer Programming, Dev, Visual Basic Journal) che straniere (ASPToday) ed è autore di testi su JavaScript e ASP.