Ho recentemente affrontato la definizione di uno schema XML per uno scambio dati.
Potevo scegliere se descrivere "attraverso esempi" la struttura del documento XML che volevo, oppure utilizzare un DTD, o definire uno SCHEMA.
Nel caso di scelta "attraverso esempi", avrei faticato molto poco per redigere la documentazione della struttura, ma avrei faticato poi a verificare che i documento XML che mi verranno forniti siano conformi alla specifica, dovendo costruire un validatore.
Utilizzando il DTD, avrei superato i problemi di definizione formale e validazione dei documenti, ma avrei fatto molta fatica a definire il DTD.
Il compromesso si ottiene utilizzando l'XML SCHEMA, che mi permette di definire formalmente la struttura dei documenti e di farne la validazione, utilizzando una sintassi non troppo complessa. Inoltre avrei avuto la possibilità di utilizzare degli SCHEMA preesistenti per alcune tipologie di dati di mio interesse.
Ho dunque scelto di redigere un XML SCHEMA. Per far ciò ho dato una occhiata a vari documenti reperibili in rete sulla sintassi. I documenti che ho trovato si dividono in due tipi: quelli troppo semplici (ovvero che si riducono a descrivere poche cose e a un piccolo esempio), e quelli troppo complicati (che affrontano la cosa partendo da molto lontano e per capire quello che c'è scritto sulla prima pagina bisogna leggere fino all'ultima). Quello che mi serviva è qualcosa che ovviamente sta nel mezzo, ovvero non troppo complesso, ma che andasse al di là del banale. Ho deciso dunque, dopo aver superato le difficoltà ed essere riuscito a terminare il mio compito di scrivere qualche nota a futura memoria.
1) Editor:
Un XML SCHEMA è un file di testo e può essere scritto con un qualsiasi editor, il consiglio è di avere un editor che quanto meno fa il coloramento sintattico delle istruzioni (gedit ad esempio), se invece si desidera un ambiente completo allora si può usare eclipse (nella versione modeling tools), che fornisce funzionalità evolute di ausilio all'editing.
2) Validatore:
Se si utilizza eclipse si può utilizzare il validatore di eclipse stesso, meglio però se si usa il validatore che sarà utilizzato in produzione, nel mio caso dovendo trattare i documenti XML tramite script PHP ho realizzato un piccolo script per effettuare la validazione.
3) Come si scrive un XML SCHEMA:
a -Intestazione:
un XML SCHEMA è un documento XML tipicamente con estensione .xsd, pertanto si inizia con la seguente frase:
<?xml version="1.0"?>
Le regole con cui va redatto sono contenute a loro volta in uno schema definito da W3C, pertanto bisogna inserire un TAG radice che fa riferimento a tale schema in questo modo:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
Questo TAG dice apre un elemento schema del namespace individuato dal prefisso xs che si riferisce allo schema http://www.w3.org/2001/XMLSchema
xs è un prefisso arbitrario, attraverso il quale si farà riferimento ai vari tipi ed elementi definiti dallo schema http://www.w3.org/2001/XMLSchema, ovvero dalla specifica XMLSchema del W3C.
Nota Bene: il fatto che il riferimento allo schema appaia come un URL non significa che tale URL debba in realtà esistere.
Nel TAG schema è opportuno inserire altre informazioni, in particolare il targetNamespace, ovvero il nome che scegliamo di dare (è arbitrario) al namespace che si origina dal nostro schema, e un riferimento allo stesso, ad esempio:
<xs:schema targetNamespace="urn:miaorg:miaapp:mioschema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="urn:miaorg:miaapp:mioschema">
Nel caso si vogliano usare strutture definite in altri schemi bisogna inserire dei riferimenti a tali schemi nel TAG schema, assegnandovi un prefisso ad esempio
<xs:schema targetNamespace="urn:miaorg:miaapp:mioschema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="urn:miaorg:miaapp:mioschema" xmlns:prv="urn:esempio:prova">
In questo modo ho aggiunto un riferimento allo schema urn:esempio:prova, tramite il prefisso prv, quindi per far riferimento a un elemento definito in tale namespace, utilizzerò una sintassi del tipo: prv:elemento
Il riferimento solo non basta, perché un validatore deve poter leggere lo schema a cui si fa riferimento, pertanto è necessario inserire un tag import con l'informazione su dove reperire lo schema, ad esempio:
<xs:import schemaLocation="schemaprova.xsd" namespace="urn:esempio:prova"></xs:import>
In questo modo ho detto che lo schema urn:esempio:prova" si trova memorizzato nel file schemaprova.xsd che si trova nella stessa cartella dello schema che sto costruendo. Posso inserire anche un pathname, con riferimenti assoluti o relativi.
Una ulteriore considerazione va fatta relativamente al parametro elementFormDefault dell'elemento schema. Di default tale parametro vale "unqualified", in questo caso un XML che utilizzerà il nostro schema può riferirsi agli elementi dello schema senza prefisso (è però obbligatorio indicare un prefisso per l'elemento radice). Se si specifica il valore "qualified" allora tutti gli elementi devono essere preceduti da prefisso (si può però non indicare il prefisso nell'elemento radice e di conseguenza non usare prefissi).
il TAG schema deve racchiudere tutto il resto del documento e essere chiuso alla fine
</xs:schema>
Riassumendo, il nostro schema per il momento appare come segue:
<?xml version="1.0"?>
<xs:schema targetNamespace="urn:miaorg:miaapp:mioschema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="urn:miaorg:miaapp:mioschema" xmlns:prv="urn:esempio:prova">
<xs:import schemaLocation="schemaprova.xsd" namespace="urn:esempio:prova"></xs:import>
<!-- qui devo inserire lo schema vero e proprio -->
</xs:schema>
b - Contenuto
Il contenuto della schema è sostanzialmente costituito da definizione di tipi, attributi, ed elementi.
Le definizioni di tipo possono essere inserite all'interno delle definizioni di elemento, ma è consigliabile separarle.
I tipi possono essere semplici o complessi.
I tipi semplici derivano da un tipo aggiungendo restrizioni (es. massima lunghezza, numero di occorrenze...)
I tipi complessi si ottengono strutturando insieme più tipi, attraverso elementi.
Gli elementi rappresentano i TAG che saranno disponibili per redigere documenti XML basati sul nostro schema.
Un primo esempio di definizione di un elemento è:
<xs:element name="TITOLO" type="xs:string"/>
in cui si definisce un elemento di nome "TITOLO" di tipo stringa (tipo di base definito nello schema W3C).
Esempio di tipo semplice:
<xs:simpleType name="stringa255">
<xs:restriction base="xs:string">
<xs:whiteSpace value="collapse"></xs:whiteSpace>
<xs:minLength value="0"></xs:minLength>
<xs:maxLength value="255"></xs:maxLength>
</xs:restriction>
</xs:simpleType>
In questo esempio si definisce un tipo semplice dal nome "stringa255", che definisce una stringa con lunghezza variabile da 0 (stringa vuota) a 255 caratteri, in cui i trailing spaces non vengono considerati
Esempio di tipo complesso:
<xs:complexType name="tipoPERSONA">
<xs:sequence>
<xs:element name="NOME" type="stringa255"
minOccurs="1" maxOccurs="1" />
<xs:element name="COGNOME" type="stringa255"
minOccurs="1" maxOccurs="1" />
</xs:sequence>
</xs:complexType name="tipoPERSONA">
Questo esempio definisce un tipo complesso di nome "tipoPERSONA" costituito dalla sequenza di due elementi di tipo stringa denominati "NOME" e "COGNOME". Tali elementi devono essere presenti obbligatoriamente (minOccurs="1") e non devono essere ripetuti (maxOccurs="1"). Gli elementi devono obbligatoriamente essere nella sequenza indicata, ovvero prima "NOME" e poi "COGNOME". E' ora possibile definire un elemento che usi questo tipo, ad esempio:
<xs:element name="PERSONA" type="tipoPERSONA">
Se si vuole far riferimento a entità definite in uno schema esterno a cui si è fatto riferimento nel TAG schema, è sufficiente utilizzare il prefisso assegnato per lo schema esterno. Ad esempio:
<xs:element name="TELEFONO">
<xs:complexType>
<xs:sequence>
<xs:element name="PREFISSO" type="prv:tipoPREFISSO"/>
<xs:element name="NUMERO" type="prv:tipoNUMERO"/>
</xs:sequence>
</xs:complexType>
</xs:element>
In questo caso abbiamo definito un elemento di nome "TELEFONO", composto dalla sequenza di due elementi il cui tipo è definito in uno schema esterno.
Un XMLSchema completo di esempio è il seguente:
<?xml version="1.0"?>
<xs:schema targetNamespace="urn:miaorg:miaapp:mioschema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="urn:miaorg:miaapp:mioschema" xmlns:prv="urn:esempio:prova">
<xs:import schemaLocation="schemaprova.xsd" namespace="urn:esempio:prova"></xs:import>
<xs:simpleType name="stringa255">
<xs:restriction base="xs:string">
<xs:whiteSpace value="collapse"></xs:whiteSpace>
<xs:minLength value="0"></xs:minLength>
<xs:maxLength value="255"></xs:maxLength>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="tipoPERSONA">
<xs:sequence>
<xs:element name="NOME" type="stringa255" minOccurs="1" maxOccurs="1" />
<xs:element name="COGNOME" type="stringa255" minOccurs="1" maxOccurs="1" />
</xs:sequence>
</xs:complexType name="tipoPERSONA">
<xs:element name="PERSONA" type="tipoPERSONA">
</xs:schema>
c - Verifica e Utilizzo
per testare lo schema prodotto, bisogna realizzare un documento XML conforme alla sintassi descritta dallo schema e validarlo.
Un documento xml conforme allo schema realizzato è il seguente:
<?xml version="1.0" ?>
<p:PERSONA xmlns:p="urn:miaorg:miaapp:mioschema" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:schemaLocation="urn:miaorg:miaapp:mioschema ./xsd/mioschema.xsd ">
<NOME>Mario</NOME>
<COGNOME>Rossi</COGNOME>
</p:PERSONA>
Da notare che si usa l'elemento PERSONA preceduto dal prefisso p, mentre per gli elementi NOME e COGNOME non c'è bisogno di prefisso. Questo deriva dal non aver impostato elementFormDefault, che pertanto risulta "unqualified".
Si suppone inoltre che il file contenente lo schema "urn:miaorg:miaapp:mioschema" si chiami mioschema.xsd si trovi in una sottocartella ./xsd della cartella in cui si trova il documento xml.
Uno script php che fa la validazione del documento xml (supponendo che si chiami test.xml e stia nella stessa cartella dello script) verso lo schema "urn:miaorg:miaapp:mioschema" contenuto nel file mioschema.xsd contenuto nella sottocartella ./xsd è il seguente:
<?php
$xdoc = new DomDocument();
$xdoc->load("test.xml");
$rit=@$xdoc->schemaValidate("./xsd/mioschema.xsd");
if ($rit) echo "OK"; else echo "FAIL";
?>