Un esempio XSD
Questo capitolo mostrerà come scrivere uno schema XML. Imparerai anche che uno schema può essere scritto in diversi modi.
Un documento XML
Diamo un'occhiata a questo documento XML chiamato "shiporder.xml":
<?xml version="1.0" encoding="UTF-8"?>
<shiporder orderid="889923"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="shiporder.xsd">
<orderperson>John Smith</orderperson>
<shipto>
<name>Ola Nordmann</name>
<address>Langgt 23</address>
<city>4000 Stavanger</city>
<country>Norway</country>
</shipto>
<item>
<title>Empire Burlesque</title>
<note>Special Edition</note>
<quantity>1</quantity>
<price>10.90</price>
</item>
<item>
<title>Hide your heart</title>
<quantity>1</quantity>
<price>9.90</price>
</item>
</shiporder>
Il documento XML sopra è costituito da un elemento radice, "shiporder", che contiene un attributo richiesto chiamato "orderid". L'elemento "shiporder" contiene tre diversi elementi figlio: "orderperson", "shipto" e "item". L'elemento "item" appare due volte e contiene un "titolo", un elemento opzionale "nota", una "quantità" e un elemento "prezzo".
La riga sopra: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" indica al parser XML che questo documento deve essere convalidato rispetto a uno schema. La riga: xsi:noNamespaceSchemaLocation="shiporder.xsd" specifica DOVE risiede lo schema (qui si trova nella stessa cartella di "shiporder.xml").
Crea uno schema XML
Ora vogliamo creare uno schema per il documento XML sopra.
Iniziamo aprendo un nuovo file che chiameremo "shiporder.xsd". Per creare lo schema potremmo semplicemente seguire la struttura nel documento XML e definire ogni elemento come lo troviamo. Inizieremo con la dichiarazione XML standard seguita dall'elemento xs:schema che definisce uno schema:
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
...
</xs:schema>
Nello schema sopra utilizziamo lo spazio dei nomi standard (xs) e l'URI associato a questo spazio dei nomi è la definizione del linguaggio Schema, che ha il valore standard di http://www.w3.org/2001/XMLSchema.
Successivamente, dobbiamo definire l'elemento "shiporder". Questo elemento ha un attributo e contiene altri elementi, quindi lo consideriamo un tipo complesso. Gli elementi figlio dell'elemento "shiporder" sono circondati da un elemento xs:sequence che definisce una sequenza ordinata di sottoelementi:
<xs:element name="shiporder">
<xs:complexType>
<xs:sequence>
...
</xs:sequence>
</xs:complexType>
</xs:element>
Quindi dobbiamo definire l'elemento "orderperson" come un tipo semplice (perché non contiene attributi o altri elementi). Il tipo (xs:string) è preceduto dal prefisso dello spazio dei nomi associato allo schema XML che indica un tipo di dati dello schema predefinito:
<xs:element name="orderperson" type="xs:string"/>
Successivamente, dobbiamo definire due elementi di tipo complesso: "shipto" e "item". Iniziamo definendo l'elemento "shipto":
<xs:element name="shipto">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
Con gli schemi possiamo definire il numero di possibili occorrenze per un elemento con gli attributi maxOccurs e minOccurs. maxOccurs specifica il numero massimo di occorrenze per un elemento e minOccurs specifica il numero minimo di occorrenze per un elemento. Il valore predefinito sia per maxOccurs che per minOccurs è 1!
Ora possiamo definire l'elemento "item". Questo elemento può apparire più volte all'interno di un elemento "shiporder". Ciò viene specificato impostando l'attributo maxOccurs dell'elemento "item" su "unbounded", il che significa che possono esserci tutte le occorrenze dell'elemento "item" quante ne desidera l'autore. Si noti che l'elemento "note" è facoltativo. Lo abbiamo specificato impostando l'attributo minOccurs a zero:
<xs:element name="item" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="note" type="xs:string" minOccurs="0"/>
<xs:element name="quantity" type="xs:positiveInteger"/>
<xs:element name="price" type="xs:decimal"/>
</xs:sequence>
</xs:complexType>
</xs:element>
Possiamo ora dichiarare l'attributo dell'elemento "shiporder". Poiché questo è un attributo obbligatorio, specifichiamo use="required".
Nota: le dichiarazioni degli attributi devono sempre venire per ultime:
<xs:attribute name="orderid" type="xs:string" use="required"/>
Ecco l'elenco completo del file di schema chiamato "shiporder.xsd":
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="shiporder">
<xs:complexType>
<xs:sequence>
<xs:element name="orderperson" type="xs:string"/>
<xs:element name="shipto">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="item" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="note" type="xs:string" minOccurs="0"/>
<xs:element name="quantity" type="xs:positiveInteger"/>
<xs:element name="price" type="xs:decimal"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="orderid" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>
Dividi lo schema
Il metodo di progettazione precedente è molto semplice, ma può essere difficile da leggere e mantenere quando i documenti sono complessi.
Il metodo di progettazione successivo si basa sulla definizione di tutti gli elementi e gli attributi prima, quindi sul riferimento ad essi utilizzando l'attributo ref.
Ecco il nuovo design del file di schema ("shiporder.xsd"):
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- definition of simple elements -->
<xs:element name="orderperson" type="xs:string"/>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
<xs:element name="title" type="xs:string"/>
<xs:element name="note" type="xs:string"/>
<xs:element name="quantity" type="xs:positiveInteger"/>
<xs:element name="price" type="xs:decimal"/>
<!-- definition of attributes -->
<xs:attribute name="orderid" type="xs:string"/>
<!-- definition of complex elements -->
<xs:element name="shipto">
<xs:complexType>
<xs:sequence>
<xs:element ref="name"/>
<xs:element ref="address"/>
<xs:element ref="city"/>
<xs:element ref="country"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="item">
<xs:complexType>
<xs:sequence>
<xs:element ref="title"/>
<xs:element ref="note" minOccurs="0"/>
<xs:element ref="quantity"/>
<xs:element ref="price"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="shiporder">
<xs:complexType>
<xs:sequence>
<xs:element ref="orderperson"/>
<xs:element ref="shipto"/>
<xs:element ref="item" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute ref="orderid" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>
Utilizzo di tipi denominati
Il terzo metodo di progettazione definisce classi o tipi, che ci consentono di riutilizzare le definizioni degli elementi. Questo viene fatto nominando gli elementi simpleTypes e complexTypes e quindi puntandoli tramite l'attributo type dell'elemento.
Ecco la terza progettazione del file di schema ("shiporder.xsd"):
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="stringtype">
<xs:restriction base="xs:string"/>
</xs:simpleType>
<xs:simpleType name="inttype">
<xs:restriction base="xs:positiveInteger"/>
</xs:simpleType>
<xs:simpleType name="dectype">
<xs:restriction base="xs:decimal"/>
</xs:simpleType>
<xs:simpleType name="orderidtype">
<xs:restriction base="xs:string">
<xs:pattern value="[0-9]{6}"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="shiptotype">
<xs:sequence>
<xs:element name="name" type="stringtype"/>
<xs:element name="address" type="stringtype"/>
<xs:element name="city" type="stringtype"/>
<xs:element name="country" type="stringtype"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="itemtype">
<xs:sequence>
<xs:element name="title" type="stringtype"/>
<xs:element name="note" type="stringtype" minOccurs="0"/>
<xs:element name="quantity" type="inttype"/>
<xs:element name="price" type="dectype"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="shipordertype">
<xs:sequence>
<xs:element name="orderperson" type="stringtype"/>
<xs:element name="shipto" type="shiptotype"/>
<xs:element name="item" maxOccurs="unbounded" type="itemtype"/>
</xs:sequence>
<xs:attribute name="orderid" type="orderidtype" use="required"/>
</xs:complexType>
<xs:element name="shiporder" type="shipordertype"/>
</xs:schema>
L'elemento di restrizione indica che il tipo di dati è derivato da un tipo di dati dello spazio dei nomi W3C XML Schema. Quindi, il seguente frammento significa che il valore dell'elemento o dell'attributo deve essere un valore stringa:
<xs:restriction base="xs:string">
L'elemento di restrizione è più spesso utilizzato per applicare restrizioni agli elementi. Guarda le seguenti righe dallo schema sopra:
<xs:simpleType name="orderidtype">
<xs:restriction base="xs:string">
<xs:pattern value="[0-9]{6}"/>
</xs:restriction>
</xs:simpleType>
Ciò indica che il valore dell'elemento o dell'attributo deve essere una stringa, deve essere esattamente sei caratteri in una riga e quei caratteri devono essere un numero compreso tra 0 e 9.