Linguaggi e tecnologie per il Web
Corso di Laurea in Ingegneria Informatica e Automatica
Sapienza Università di Roma
a.a. 2015/2016
XML
Parte 4:
XML Schema
Luigi Dragone, Riccardo Rosati
I DTD sono il meccanismo "nativo" di XML per la definizione della struttura dei documenti
Essendo incentrati sui documenti sono poco adatti alla definizione di contenuti fortemente strutturati
I DTD possono essere utilizzati efficacemente per lo scambio di informazioni tra utenti, ma non tra sistemi automatici in quanto non consentono di stabilire con precisione il "tipo" delle informazioni. Storicamente i linguaggi a marcatura nascono come annotazione dei documenti testuali, ed è solo con la diffusione di XML che sono stati adoperati estensivamente per la rapresentazione delle informazioni
La specifica di un DTD non è un documento XML. Ad es.:
<!ELEMENT e (#PCDATA)>
non è una produzione XML ben formata
I meccanismi di estensione e modularizzazione dei DTD sono estremamente limitati (definizioni esterne, entità parametriche)
I DTD non sono completamente compatibili con i namespace
I DTD non permettono di stabilire vincoli di chiave ed integrità referenziale, con l'eccezione degli attributi ID ed IDREF.
XML Schema è un'applicazione XML finalizzata alla definizione
della struttura dei documenti XML, compito già svolto dai DTD, in
modo più preciso e modulare rispetto a quanto permesso da questi
ultimi.
XML Schema prevede la descrizione della struttura di un documento
con un secondo documento XML (detto schema)
Analogamente a quanto avviene con i DTD è possibile validare
un documento rispetto al proprio schema
Gli schemi XML prevedono la possibilità di creare dei modelli
dati fortemente tipati (come linguaggi di programmazione tipo C, Java o
linguaggi di specifica tipo DDL SQL) e sono compatibili con i namespace
Gli schemi XML non sono sostitutivi dei DTD, ma i due sistemi devono
essere utilizzati in concomitanza (ad es., in XML Schema non è
possibile definire le entità)
In generale per i documenti scambiati tra utenti è preferibile
utilizzare ancora i DTD, negli altri casi (ad es., strutture dati o basi
di dati) gli schemi
L'impiego degli schemi in fase di validazione è molto
più dispendioso, in termini di risorse computazionali, rispetto
ai DTD (validare solo quando necessario)
Gli schemi XML possono essere utilizzati per il data binding
XML Schema: W3C Recommendation del 2/5/2001
Definizione di un documento contenente un solo elemento di tipo
testuale.
<?xml version="1.0"?>
<E>Hello</E>
Lo schema associato è:
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="E" type="xsd:string"/>
</xsd:schema>
Il tag element
permette di definire un elemento del
documento specificandone nome e tipo.
Nella definizione di uno schema l'elemento associato alla radice del
documento (top-level element) è il primo dichiarato.
Per associare un documento (ovvero un'istanza di schema) al proprio
schema si utilizzano degli attributi associati al namespace XSI (XML
Schema Instance) sul root element, ad es:
<?xml version="1.0"?>
<E xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="schema.xsd">
Hello
</E>
In XML Schema si associa agli elementi un tipo (analogamente a
quanto avviene nella definizione delle strutture dati dei LdP) che
può essere semplice o complesso:
Un tipo complesso viene definito con il tag complexType
A differenza dei DTD è possibile specificare il tipo degli
elementi semplici.
All'interno dei documenti XML tali elementi sono rappresentati comunque
come stringhe, tuttavia è possibile restringere il campo delle
stringhe valide (ad es., solo quelle che rappresentano numeri in virgola
mobile, oppure numeri interi positivi, oppure date, oppure...).
I tipi semplici supportati sono:
float
, double
, decimal
,int
,byte
,unsignedInt
,postiveInt
)date
, timeInstant
,duration
,gYear
)ID
, IDREF
, ENTITY
)string
, normalizedString
)boolean
)uriReference
)<xsd:element name="NOME" type="xsd:string"/> <xsd:element name="CDL" type="xsd:string"/> <xsd:element name="DURATA" type="xsd:duration"/> <xsd:element name="INIZIO" type="xsd:date"/> <xsd:element name="ARGOMENTO" type="xsd:string"/> <xsd:element name="PROGETTO" type="xsd:string"/> <xsd:element name="CREDITI" type="xsd:nonNegativeInteger"/>
Il sistema dei tipi può essere esteso mediante un meccanismo di ereditarientà imponendo restrizioni sui tipi derivati (ad es., mediante espressioni regolari).
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="CORSO" type="TipoCorso"/>
<xsd:complexType name="TipoCorso">
<xsd:sequence>
<xsd:element name="NOME" type="xsd:string"/>
<xsd:element name="DOCENTE" type="xsd:string"/>
<xsd:element name="TUTOR" type="xsd:string"/>
<xsd:element name="CDL" type="xsd:string"/>
<xsd:element name="DURATA" type="xsd:string"/>
<xsd:element name="ARGOMENTO" type="xsd:string"/>
<xsd:element name="PROGETTO" type="xsd:string"/>
<xsd:element name="CREDITI" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
Il documento è formato da un elemento associato al tag CORSO
di tipo complesso TipoCorso che contiene una sequenza di
elementi di tipo stringa. La definizione DTD "equivalente" sarebbe stata:
<!ELEMENT CORSO (NOME, DOCENTE, TUTOR, CDL, DURATA, ARGOMENTO, PROGETTO, CREDITI)>
Un'istanza del precedente schema è:
<CORSO>
<NOME>Progetto di Linguaggi e Traduttori</NOME>
<DOCENTE>Riccardo Rosati</DOCENTE>
<TUTOR>Luigi Dragone</TUTOR>
<CDL>Ing. Informatica</CDL>
...
<CORSO>
Analogamente all'impiego delle espressioni regolari per la
definizione del content model degli elementi, anche in XML Schema
è possibile stabilire le cardinalità minime e massime dei
vari elementi con l'uso degli attributi minOccurs e maxOccursche
possono assumere un qualasiasi valore numerico intero >=0
oppure
unbounded
per indicare un
numero illimitato.
Se un elemento è opzionale allora il numero minimo di
occorrenze è 0.
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="CORSO" type="TipoCorso"/>
<xsd:complexType name="TipoCorso">
<xsd:sequence>
<xsd:element name="NOME" type="xsd:string"/>
<xsd:element name="DOCENTE" type="xsd:string"/>
<xsd:element name="TUTOR" type="xsd:string"
minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="CDL" type="xsd:string"/>
<xsd:element name="DURATA" type="xsd:string"/>
<xsd:element name="ARGOMENTO" type="xsd:string"
minOccurs="1" maxOccurs="unbounded"/>
<xsd:element name="PROGETTO" type="xsd:string"
minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="CREDITI" type="xsd:string"
minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
<CORSO>
<NOME>Linguaggi e tecnologie per il Web</NOME>
<DOCENTE>Riccardo Rosati</DOCENTE>
<TUTOR>Riccardo Rosati</TUTOR>
<CDL>Ing. Informatica</CDL>
<DURATA>60 ore</DURATA>
<ARGOMENTO>Parsing</ARGOMENTO>
<ARGOMENTO>HTML</ARGOMENTO>
<ARGOMENTO>XML</ARGOMENTO>
<ARGOMENTO>Programmazione Web lato client</ARGOMENTO>
<CREDITI>6</CREDITI>
<CORSO>
Per definire elementi a contenuto testuale, ci sono due casi:
Esempio: dichiarazione di un elemento <a>
contenente un testo di tipo intero e un attributo <attr>
di tipo stringa:
<xsd:element name="a"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:integer"> <xsd:attribute name="attr" type="xsd:string" /> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element>
In XML Schema è possibile definire tipi a contenuto misto, ovvero contenenti sia parti testuali che altri elementi (e in modo più potente rispetto al mixed content model della DTD).
Esempio di dichiarazione di elemento <a>
contenente sia parti testuali l'elemento <b>
:
<xsd:element name="a"> <xsd:complexType mixed="true"> <xsd:element name="b" type="tipo1"/> </xsd:complexType> </xsd:element>
Esempio di dichiarazione di elemento <a>
contenente sia parti testuali che gli elementi <b>
, <c>
, <d>
:
<xsd:element name="a"> <xsd:complexType mixed="true"> <xsd:sequence> <xsd:element name="b" type="tipo1"/> <xsd:element name="c" type="tipo2"/> <xsd:element name="d" type="tipo1"/> </xsd:sequence> </xsd:complexType> </xsd:element>
In XML Schema è possibile dichiarare elementi a contenuto vuoto (analogamente al content model EMPTY
della DTD).
<a>
vuoto (e senza attributi):
<xsd:element name="a"> <xsd:complexType/> </xsd:element>Esempio di dichiarazione di un elemento
<a>
vuoto con un attributo attr
di tipo intero positivo:
<xsd:element name="a"> <xsd:complexType> <xsd:attribute name="attr" type="xsd:positiveInteger"/> </xsd:complexType> </xsd:element>
Un elemento incluso in un tipo complesso può essere a sua
volta associato ad un tipo complesso.
In tal modo i tipi possono essere composti, inoltre le definizione
di un tipo può essere condivisa tra più elementi (anche se
appartenenti a tipi diversi).
Una funzionalità di questo tipo può essere ottenuta
con i DTD mediante l'impiego delle entità parametriche, ma
risulta di difficile applicabilità.
Ad esempio il docente e gli eventuali tutori possono avere un nominativo ed un recapito.
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="CORSO" type="TipoCorso"/>
<xsd:complexType name="TipoPersona">
<xsd:sequence>
<xsd:element name="NOMINATIVO" type="xsd:string"/>
<xsd:element name="RECAPITO" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TipoCorso">
<xsd:sequence>
<xsd:element name="NOME" type="xsd:string"/>
<xsd:element name="DOCENTE" type="TipoPersona"/>
<xsd:element name="TUTOR" type="TipoPersona"
minOccurs="0" maxOccurs="unbounded"/>
...
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
<CORSO>
...
<TUTOR>
<NOMINATIVO>Luigi Dragone</NOMINATIVO>
<RECAPITO>dragone@dis.uniroma1.it</RECAPITO>
</TUTOR>
...
</CORSO>
Il tipo di un elemento può essere dichiarato all'interno
all'elemento stesso (anonymous type), in tale caso la definizione non
può essere condivisa.
Si tratta di un caso analogo all'uso delle classi anonime in Java.
Ad esempio, il nominativo è suddiviso in nome e cognome:
<xsd:complexType name="TipoPersona">
<xsd:sequence>
<xsd:element name="NOMINATIVO">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="NOME" type="xsd:string"/>
<xsd:element name="COGNOME" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="RECAPITO" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<CORSO>
...
<TUTOR>
<NOMINATIVO><NOME>Luigi</NOME><COGNOME>Dragone</COGNOME></NOMINATIVO>
<RECAPITO>dragone@dis.uniroma1.it</RECAPITO>
</TUTOR>
...
</CORSO>
Il raggruppamento degli elementi all'interno della definizione di un
tipo può avvenire in 3 modalità
sequence
), equivalente
all'operatore ,
delle espressioni dei content model all
), simile
all'operatore ?
delle espressioni dei content model SGML,
ma non XMLchoice
), equivalente
all'operatore |
delle espressioni dei content modelL'impiego dell'elemento all
permette di specificare
la presenza di un insieme di elementi indipendentemente dall'ordine. Gli
elementi devono essere specificati con cardinalità massime e
minime ristrette ai soli valori 0 ed 1.
Ad esempio, nel nominativo di una persona non è rilevante l'ordine del nome e del cognome:
<xsd:complexType name="TipoNominativo">
<xsd:all>
<xsd:element name="NOME" type="xsd:string"
minOccurs="1" maxOccurs="1"/>
<xsd:element name="COGNOME" type="xsd:string"
minOccurs="1" maxOccurs="1"/>
</xsd:all>
</xsd:complexType>
<CORSO>
...
<TUTOR>
<NOMINATIVO><COGNOME>Dragone</COGNOME><NOME>Luigi</NOME></NOMINATIVO>
<RECAPITO>dragone@dis.uniroma1.it</RECAPITO>
</TUTOR>
...
</CORSO>
Le scelte alternative possono essere combinate con le sequenze, analogamente a quanto avviene nei content model dei DTD, e specificare un intervallo di cardinalità ammissibili (ripetizioni).
<xsd:complexType name="TipoOrario">
<xsd:sequence>
<xsd:element name="DURATA" type="xsd:string"/>
<xsd:choice minOccurs="1" maxOccurs="unbounded">
<xsd:element name="LEZIONE" type="TipoLezione"/>
<xsd:element name="ESERCITAZIONE" type="TipoEsercitazione"/>
<xsd:element name="SEMINARIO" type="TipoSeminario"/>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
Nel caso in cui lo stesso elemento può comparire all'interno di più elementi, è possibile usare l'attributo ref
di <xsd:element>
. Usando tale attributo al posto dell'attributo name
, si fa riferimento alla dichiarazione dell'elemento il cui nome è il valore dell'attributo ref
.
Ad esempio, il seguente frammento di schema stabilisce che l'elemento <a>
compare nel content model degli elementi <b>, <c>, <d>
, senza ripetere più volte la dichiarazione dell'elemento <a>
:
<xsd:element name="a"> <xsd:complexType> ... </xsd:complexType> </xsd:element> <xsd:element name="b"> <xsd:complexType> <xsd:element ref="a"> </xsd:complexType> </xsd:element> <xsd:element name="c"> <xsd:complexType> <xsd:element ref="a"> </xsd:complexType> </xsd:element> <xsd:element name="d"> <xsd:complexType> <xsd:element ref="a"> </xsd:complexType> </xsd:element>
La definizione dei tipi complessi ammette la possibilità di specificare i relativi attributi. Analogamente agli elementi anche gli attributi sono fortemente tipati ed è possibile specificare l'obbligatorietà oppure il valore predefinito.
<xsd:complexType name="TipoCorso">Possono essere definiti anche gruppi di attributi condivisi da più tipi/elementi.
<xsd:sequence>
<xsd:element name="NOME" type="xsd:string"/>
...
</xsd:sequence>
<xsd:attribute name="codice" type="xsd:string" use="required"/>
<xsd:attribute name="homePage" type="xsd:uriReference"/>
</xsd:complexType>
A differenza dei DTD, gli schemi sono compatibili con i namespace.
L'elemento schema possiede un attributo (targetNamespace) che
specifica l'URI del namespace associato agli elementi in corso di
definizione. Si deve specificare che gli elementi appartengono a tale
namespace, mentre gli attributi in genere non sono associati a nessun
namespace.
<?xml version="1.0"?>
<xsd:schema
xmlns="urn:dis.uniroma1.it:corso"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xsd:targetNamespace="urn:dis.uniroma1.it:corso"
xsd:elementFormDefault="qualified"
xsd:attributeFormDefault="unqualified">
<xsd:element name="CORSO" type="TipoCorso"/>
...
</xsd:schema>
L'impiego dei namespace richiede l'uso di un diverso costrutto per
referenziare lo schema
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<corso:CORSO xmlns:corso="urn:dis.uniroma1.it:corso"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:dis.uniroma1.it:corso http://www.dis.uniroma.it/schema/corso.xsd">
...
</corso:CORSO>
L'URI del namespace è indipendente da quella dello schema.
Mentre la prima non deve essere mai risolta (ovvero convertita in un
indirizzo reale), la seconda deve puntare ad un'istanza del documento
contentente lo schema. Si può associare anche ad uno schema
un'indirizzo "virtuale" mediante un'URN, in tale caso il parser deve
possedere una copia interna dello schema in questione, analogamente a
quanto fatto dagli attuali browser web per il DTD di HTML.
Una delle principali limitazioni dei DTD risiede nella gestione dei vincoli di unicità e di integrità referenziale.
Il meccanismo basato sull'impiego di attributi di tipo ID ed IDREF è estremamente limitato, in quanto l'unicità degli elementi non dipende dai valori propri, ma da un identificatore esterno.
Ad es.: non è possibile stabile che una persona sia identificata univocamente dal proprio none e cognome
Le basi dati permettono di definitire vincoli di più sofisticati. XML Schema introduce dei costrutti analoghi anche per XML basati sull'impiego di espressioni XPath.
unique
)key
)keyRef
)I vincoli sono validi nell'ambito di dichiarazione (ad es., singolo elemento o intero documento) e sono caratterizzati da:
selector
) che identifica
mediante un'espressione XPath gli elementi interessatifield
) che specifica
i nodi interessati dal vincolo mediante espressioni XPath relative ai
nodi identificati dal selettoreNB: I vincoli d'integrità sono associati agli elementi non ai tipi.
Rispetto al meccanismo standard di XML:
NB: La verifica dei vincoli d'integrità può essere estremamente onerosa, pertanto devono essere usati con accortezza
include
) di schemi che definiscono tipi
all'interno dello stesso namespace dello schema includenteimport
) di schemi che definiscono tipi in
qualsiasi namespaceL'uso degli schemi permette di gestire più facilmente il
problema dell'associazione di strutture dati tipiche dei LdP (in
particolare OO) ed i documenti XML. Tale problema viene denominato data
binding. Il problema è diventato particolarmente rilevante
non tanto per l'uso dei DB XML, quanto per l'impiego di XML come veicolo
dati per i web service (serializzazione su socket).
In genere il problema della serializzazione e deserializzazione di
strutture dati in XML viene trattato sfruttando apposite API (ad es.,
DOM e SAX)
Esistono degli strumenti che partendono da una specifica (schema XML
oppure un diagramma delle classi) sono in grado di gestire
automaticamente il problema della serializzazione da e verso XML.
In particolare gli strumenti guidati da XML producono delle classi
che rappresentano i data object definiti dal documento (ad es., un
complex type corrisponde ad una classe, mentre un elemento ad un
riferimento piuttosto che ad un attributo).
Le maggiori difficoltà si incontrano quando sia la struttura
XML che quella OO sono fissate ed è necessario costruire un
adattatore. Non esiste una tecnica generale capace di risolvere tutti i
problemi di ristrutturazione (a parte XSLT e sviluppo di adattatori
ad-hoc), anche se gli strumenti possiedono un elevato livello di
configurabilità del binding.
Tra gli strumenti disponbili per Java abbiamo:
XML Schema Part 0: Primer W3C Recommendation 2 May 2001
XML Schema Part 1:
Structures W3C Recommendation 2 May 2001
XML Schema Part 2:
Datatypes W3C Recommendation 2 May 2001