XML - Schema Mario Arrigoni Neri
XML ben formati ed XML validi La buona forma di un documento XML è una proprietà puramente sintattica Tutti i tag sono chiusi, propriamente innestati ed esiste un’unica radice… La validazione è invece già “semantica”, nel senso che ha a che fare con il significato dei dati e l’utilizzo del documento Commitment sulla struttura del contenuto Mi impegno ad inviare articoli composti da un titolo, la lista degli autori, un abstract ed una serie di capitoli, ciascuno con un titolo e vari paragrafi, ed ogni immagine con la sua didascalia.
XML per l’accesso ai documenti E’ relativamente poco human-readable Pensato per essere letto/scritto da sistemi artificiali Nasce per scrivere documenti Metalinguaggio per costruire formati proprietari Più semplice di SGML Enfasi su: Facilità di elaborazione Layer standard (parser) Struttura ad albero dei documenti Applicazione XML parser DTD XML
XML per la comunicazione XML è anche un formato per il “trasporto” dell’informazione Trasferimento di dati tra applicazioni Interoperabilità delle applicazioni Servizi standard per validare la conformità agli specifici linguaggi La struttura ad albero è sufficientemente generale da adattarsi a tutte le applicazioni, ma sufficientemente ben caratterizzata per la realizzazione di parser generici DTD Appl. 2 Appl. 1 Formato interno 2 Formato interno 1 XML
Perché XML-S ? DTD è poco pratico e poco espressivo per le esigenze di comunicazione Limiti dei DTD Namespace: come già visto è difficile far coesistere DTD e namespace perché i primi sono nati con XML, mentre i namespace sono stati introdotti successivamente Elementi di testo: non è possibile imporre vincoli al contenuto testuale e, soprattutto, agli attributi. Non esiste il concetto di testo “tipizzato” es: <corso codice=“Ing.Conoscenza”> <numeroIscritti>Marco</numeroIscritti> </corso> Content model misti: è possibile comporli solo come (#PCDATA|..|..)* Documentazione: con i DTD posso solo inserire i commenti XML, che però possono essere ignorati dal parser I DTD NON sono scritti in XML !!!
XSD XSD (XML Schema Definition) è una particolare applicazione XML (linguaggio) che serve a descrivere le regole di validità di un altro linguaggio Risposta all’inadeguatezza di DTD (probabile sostituzione di fatto) Supporto estensivo per la qualificazione tramite namespace Un sistema di tipi gerarchico Tipizzazione del testo Tipizzazione dei contenuti Definizione di frammenti di specifica riutilizzabili Permette di specificare vincoli per elementi strutturati ed offre grande flessibilità per Content Model misti Documentazione esplicita Ovviamente è scritto in XML Non ci sono pasti gratis: è più complesso e “prolisso” del DTD (fattore 1:4)
Struttura di un XML Schema XSD fa riferimento al namespace “http://www.w3.org/2001/XMLSchema” Un documento XSD è racchiuso in un elemento <schema> <xsd:schema xmlns:xsd= http://www.w3.org/2001/XMLSchema> </xsd:schema> Il documento si articola in una serie di definizioni di tipi ed elementi XML Schema usa i tipi per specificare i vincoli sul contenuto degli elementi e degli attributi <xsd:element name=“…” type=“…”/> <xsd:attribute name=“…” type=“…”/> I tipi possono essere: Semplici: un tipo semplice non può contenere markup o attributi. Si tratta di restrizioni di #PCDATA e CDATA Complessi: un tipo complesso è l’analogo dei tipi strutturati (element content) e misti (mixed content) del DTD
Tipi semplici In maniera analoga ai comuni linguaggi di programmazione i tipi semplici possono essere built-in o user-defined I tipi sono tutti qualificati. Es: xsd:string Tipi built-in: string, boolean, decimal, float, Date (es: ‘2004-01-10’), time (es: ’13:00:00+01:00’) ID ed IDREF: con lo stesso significato del DTD Ecc… Tipi semplici user-defined (o derivati) <xsd:simpleType name=“..”> … </xsd:simpleType> In generale un tipo può essere anonimo quando la sua attribuzione è desunta dalla collocazione fisica dell’elemento XML che lo definisce
Derivazione per restrizione - 1 Il metodo classico per derivare tipi user-defined è quello di partire da un tipo già noto e restringere i valori assumibili Ogni tipo semplice ha delle caratteristiche (facets) che possono essere usate nella restrizione Facets length, minLength, maxLength : numero di elementi (es: caratteri) minExclusive, minInclusive, maxExclusive, maxInclusive enumeration ecc…
Derivazione per restrizione - 2 <xsd:simpleType name=“anno”> <xsd:restriction base=“xsd:integer”> <xsd:minInclusive value=“0”/> <xsd:maxInclusive value=“9999”/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name=“anno”> <xsd:restriction base=“xsd:nonNegativeInteger”> <xsd:precision value=“4”/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name=“salutation”> <xsd:restriction base=“xsd:string”> <xsd:enumeration value=“Mr”/> <xsd:enumeration value=“Mrs”/> … </xsd:restriction> </xsd:simpleType>
Restrizione tramite pattern Particolare metodo di restrizione Utilizza una sintassi apposita per descrivere i valori ammissibili tramite espressioni regolari (simili al Perl) a? , a a+: a, aa, aaaaa, … a* : , a, aa, aaaa, … [abcd]/(a|b|c|d) a, b, c, d [a-z] a, b, c, …, z a{2,4} aa, aaa, aaaa [^0-9]+ sequenza di non cifre <xsd:simpleType name=“telefono”> <xsd:restriction base=“xsd:string”> <xsd:pattern value=“(0039-)?0[0..9]{1,3}-[0..9]+)”/> </xsd:restriction> </xsd:simpleType>
Derivazione per unione I valori assumibili sono l’unione dei valori assumibili da due tipi semplici <xsd:simpleType name=“Tpositivo”> <xsd:restriction base="xsd:decimal"> <xsd:minExclusive value="0.0"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name=“Tgratis”> <xsd:restriction base="xsd:string"> <xsd:enumeration value="gratis"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="Tprezzo"> <xsd:union membersTypes=“Tpositivo Tgratis”/> </xsd:simpleType>
Derivazione per lista - 1 Fino ad ora abbiamo visto solo tipi scalari E’ possibile definire come tipo semplice la lista, divisa da spazi, di altri tipi semplici. Tipo strutturato omogeneo.. Analogo agli array dei linguaggi di programmazione <xsd:simpleType name=“Tpositivo”> <xsd:restriction base="xsd:decimal"> <xsd:minExclusive value="0.0"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name=“TlistaDiPositivi”> <xsd:list itemType=“TPositivo”/> </xsd:simpleType> <xsd:element name=“valore” type=“TlistaDiPositivi”> <valore>1 2 34 88</valore>
Derivazione per lista - 2 Con i tipi lista il facet “length” si riferisce ai componenti <xsd:simpleType name=“Tpositivo”> <xsd:restriction base="xsd:decimal"> <xsd:minExclusive value="0.0"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name=“TlistaDiPositivi”> <xsd:list itemType=“TPositivo”/> </xsd:simpleType> <xsd:simpleType name=“TlistaDiSeiPositivi”> <xsd:restriction base=“TlistaDiPositivi”> <xsd:length value=“6”/> </xsd:restriction> </xsd:simpleType>
Tipi anonimi - 1 In ogni occasione in cui devo fare riferimento ad un tipo posso di fatto definirlo in un elemento interno <xsd:simpleType name=“TlistaDiPositivi”> <xsd:list> <xsd:simpleType name=“Tpositivo”> <xsd:restriction base="xsd:decimal"> <xsd:minExclusive value="0.0"/> </xsd:restriction> </xsd:simpleType> </xsd:list> </xsd:simpleType> <xsd:simpleType name="Tprezzo"> <xsd:union> <xsd:simpleType> <xsd:restriction base="xsd:decimal"> <xsd:minExclusive value="0.0"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:enumeration value="gratis"/> </xsd:restriction> </xsd:simpleType> </xsd:union> </xsd:simpleType> <xsd:simpleType name=“TlistaDiPositivi”> <xsd:restriction> <xsd:simpleType>… </xsd:simpleType> </xsd:restriction> </xsd:simpleType>
Tipi anonimi - 2 Questo vale anche e soprattutto nel caso in cui un tipo venga utilizzato una sola volta. Nel DTD non c’è distinzione tra elementi (o attributi) e tipi, corrispondenza 1:1 <xsd:element name=“prezzo”> <xsd:simpleType> … </xsd:simpleType> </xsd:element> <xsd:simpleType name=“Tprezzo”> </xsd:simpleType> <xsd:element name=“prezzo” type=“Tprezzo”/>
Tipi complessi I tipi complessi sono I content vuoti e generici (EMPTY ed ANY del DTD) Element content Mixed content Qualunque elemento con attributi Il concetto centrale è quello di aggregazione (tipi strutturati) Tipo non scalare disomogeneo per aggregazione. Analogo alle strutture dei linguaggi di programmazione
Content model ANY ed EMPTY Si costruiscono sulla base dei tipi predefiniti xsd:anyType ed xsd:complexType ANY content è definito come xsd:anyType EMPTY content è un complexType per cui non si specifica nessun componente <xsd:element name=“memo” type=“xsd:anyType”/> <xsd:complexType name=“empty”/> <xsd:element name=“br” type=“empty”/>
Element content - 1 XSD utilizza degli elementi appositi per esprimere la struttura dei sottoelementi di un element content (DTD usava le espressioni regolari) Dato che XSD gestisce separatamente tipi ed istanze occorre assegnare ad ogni sottoelemento sia il nome (tag) che il tipo (struttura del contenuto e degli attributi) Sequenza (A, B, …) Esempio: <xsd:complexType name=“note”> <xsd:sequence> <xsd:element name=“title” type=“xsd:string”/> <xsd:element name=“from” type=“xsd:string”/> <xsd:element name=“to” type=“xsd:string”/> </xsd:sequence> </xsd:complexType> <xsd:sequence> <xsd:element name=“A” type=“tipoA”/> <xsd:element name=“B” type=“tipoB”/> … </xsd:sequence>
Element content - 2 alternativa (A | B | …) Insieme (A & B & …) tutti gli elementi (come sequence), ma senza vincoli sull’ordinamento presente in SGML ma eliminato dal DTD <xsd:choice> <xsd:element name=“A” type=“tipoA”/> <xsd:element name=“B” type=“tipoB”/> … </xsd:choice> <xsd:all> <xsd:element name=“A” type=“tipoA”/> <xsd:element name=“B” type=“tipoB”/> … </xsd:all>
Element content - 3 A? / A+ / A* A? A+ A* XSD fornisce un costrutto più generale, che permette di indicare cardinalità minima e massima di ogni sottoelemento e di ogni costrutto di tipo (sequence, ecc..) in maniera simile a xsd:pattern xsd:minOccurs: numero di occorrenze minime xsd:maxOccurs: numero massimo di occorrenze. Può essere “unbounded” Entrambi hanno per default il valore “1” A? A+ A* <xsd:element name=“…” type=“..” minOccurs=“0”/> <xsd:element name=“…” type=“..” maxOccurs=“unbounded”/> <xsd:element name=“…” type=“..” maxOccurs=“unbounded” minOccurs=“0”/>
Element content complessi Come avviene con i DTD i costrutti possono combinarsi per formare espressioni regolari <!ELEMENT sezione (titolo, (sottotitolo | abstract)?, para+)> <xsd:element name=“sezione”> <xsd:complexType> <xsd:sequence> <xsd:element name=“titolo” type=“xsd:string”/> <xsd:choice minOccurs=“0”> <xsd:element name=“sottotitolo” type=“xsd:string”/> <xsd:element name=“abstract” type=“xsd:string”/> </xsd:choice> <xsd:element name=“para” type=“xsd:string” maxOccurs=“unbounded”/> <xsd:sequence> </xsd:complexType> </xsd:element>
Mixed content - 1 Sintatticamente, la definizione di un tipo complesso con contenuto misto richiede semplicemente di specificare l’attributo mixed=“true”. <!ELEMENT testo (#PCDATA | bold | italic)*> <xsd:complexType name=“TipoTesto” mixed=“true”> <xsd:choice minOccurs=“0” maxOccurs=“unbounded”> <xsd:element name=“bold” type=“xsd:string”/> <xsd:element name=“italic” type=“xsd:string”/> <xsd:choice> </xsd:complexType> <xsd:element name=“testo” type=“TipoTesto”>
Mixed content - 2 La maggiore generalità dell’XSD permette di esprimere vincoli più precisi. Ad esempio è semplice forzare l’ordine degli elementi. Oppure si obbliga l’XML ad avere tutti i sottoelementi, anche se inframezzati da testo <xsd:complexType name=“testo” mixed=“true”> <xsd:sequence> <xsd:element name=“bold” type=“xsd:string” minOccurs=“0” /> <xsd:element name=“italic” type=“xsd:string” minOccurs=“0” /> <xsd:sequence> </xsd:complexType> <xsd:complexType name=“testo” mixed=“true”> <xsd:all> <xsd:element name=“bold” type=“xsd:string”/> <xsd:element name=“italic” type=“xsd:string”/> <xsd:all> </xsd:complexType>
Derivazione di tipi complessi I tipi complessi possono essere derivati sia per restrizione che per estensione Derivazione per restrizione: si limitano i valori assumibili dall’elemento all’interno del documento XML. Rafforzamento dei vincoli minOccurs e maxOccurs Tipizzazione più precisa di un sottoelemento o di un attributo Assegnamento di un valore preciso a sottoelementi o attributi Derivazione per estensione : Si aggiungono sottoelementi e/o attributi Le due tecniche corrispondono alle due tipologie di eredità dei linguaggi di programmazione
Derivazione per restrizione Il TestoConEffetti è un testo con almeno un elemento bold o italic Può essere usato ogni volta che ci si aspetterebbe “TipoTesto” Altre restrizioni sono: Impostare un default per gli elementi Assegnare un valore fisso o specificare il tipo Restringere i minOccurs-maxOccurs <xsd:complexType name=“TipoTestoConEffetti” mixed=“true”> <xsd:restriction base=“TipoTesto”> <xsd:choice minOccurs=“1” maxOccurs=“unbounded”> <xsd:element name=“bold” type=“xsd:string”/> <xsd:element name=“italic” type=“xsd:string”/> <xsd:choice> </xsd:restriction> </xsd:complexType> <xsd:element name=“testo” type=“TipoTesto”>
Derivazione per estensione Si aggiungono elementi e/o attributi <xsd:complexType name=“TipoTestoInternazionale” mixed=“true”> <xsd:extension base=“TipoTesto”> <xsd:sequence> <xsd:element name=“estratto” type=“xsd:string”/> <xsd:sequence> <xsd:attribute name=“language” type=“xsd:string”/> </xsd:extension> </xsd:complexType> <xsd:element name=“testo” type=“TipoTesto”>
Tipi e content model Formalmente la definizione dei sottoelementi costituisce il ContentModel, mentre il Tipo è dato dal ContentModel e dagli eventuali attributi Diventa possibile distinguere tra tipi complessi con contenuto semplice o complesso <xsd:complexType name=“prezzo”> <xsd:simpleContent> <xsd:extension base=“xsd:decimal”> <xsd:attribute name=“valuta” type=“xsd:string”/> </xsd:extension> </xsd:simpleContent> </xsd:complexType>
Definizioni globali Una definizione è globale se è direttamente all’interno dell’elemento <schema> Invece che assegnare un nome locale ad un elemento è possibile riferirsi ad un elemento globale, riutilizzandone la definizione attraverso l’attributo ref <xsd:element name=“nome” type=“xsd:string”/> <xsd:element name=“cognome” type=“xsd:string”/> <xsd:complexType name=“nomeECognome”> <xsd:sequence> <xsd:element ref=“nome”/> <xsd:element ref=“cognome”/> </xsd:sequence> </xsd:complexType>
XSD e namespace - 1 Uno schema è una collezione di tipi ed elementi appartenenti ad uno specifico namespace, detto targetnamespace Quando vogliamo verificare la validità del documento lo facciamo in relazione ad uno o più schemi. Ci serve sapere quali tag considerare per ogni schema L’autore dello schema può specificare se gli elementi e gli attributi devono essere qualificati tramite prefissi o tramite il namespace di default
XSD e namespace - 2 L’attributo targetNamespace dell’elemento <schema> specifica il nameSpace associato alle componenti dello schema Gli attributi elementFormDefault ed attributeFormDefault specificano se gli elementi e gli attributi non globali devono essere qualificati <xsd:schema xmlns:xsd=“http://www.w3.org/2001/XMLSchema” xmlns:note=“http://www.elet.polimi.it” targetNamespace=“http://www.elet.polimi.it/” elementFormDefault=“unqualified” attributeFormDefault=“unqualified”> <xsd:simpleType name=“tm”><xsd:restriction base=“”…><>… <xsd:element name=“note”> <xsd:complexType><xsd:sequence> <xsd:element name=“from” type=“xsd:string”/> <xsd:element name=“to” type=“xsd:string”/> <xsd:element name=“message” type=“note:tm”/> </xsd:sequence></xsd:complexType></xsd:element> </xsd:schema>
XSD e namespace - 3 Solo gli elementi globali possono essere radici di un elemento Con i valori di default (unqualified) solo gli elementi e gli attributi globali sono qualificati <?xml version=“1.0”?> <note:note xmlns:note=“http://www.elet.polimi.it”> <note:from>Marco</note:from> <note:to>Luca</note:to> <note:message>Nota di prova</note:message> </note:note> errore
XSD e namespace - 4 E’ possibile dare indicazioni al parser per controllare la coesistenza con elementi di altri namespace <xsd:complexType name=“lista”> <xsd:element name=”nodo” maxOccurs=“unbounded”> <xsd:complexType> <xsd:sequence> <xsd:any namespace=“www.elet.polimi.it”/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:complexType> Lista generica di elementi appartenenti al namespace “www.elet.polimi.it” Lista generica di elementi NON appartenenti al namespace “www.elet.polimi.it” … <xsd:sequence> <xsd:other namespace=“www.elet.polimi.it”/> </xsd:sequence> …
Modularità - 1 E’ possibile creare gruppi di elementi ed attributi riusabili E’ possibile includere uno schema esterno su cui costruire la propria descrizione <xsd:group name=“nameGroup”> <xsd:sequence> <element name=“nome” type=“xsd:string”/> <element name=“cognome” type=“csd:string”/> </xsd:sequece> </xsd:group> <xsd:attributeGroup name=“attrGroup”> <xsd:attribute name=“matricola” type=“xsd:integer”/> </xsd:attributeGroup> <xsd:element name=“dipendente”> <xsd:complexType> <xsd:group ref=“nameGroup”/> <xsd:attributeGroup ref=“attrGroup”/> </xsd:complexType> </xsd:element> <import namespace=“…” schemaLocation=“…”/>
Modularità - 2 Substitution Groups: è un meccanismo che permette di sostituire elementi con altri elementi Ogni gruppo associa ad un elemento globale una serie di elementi che gli possono essere sostituiti Gli elementi shipComment e customerComment possono sostituire comment nel particolare documento XML <xsd:element name=“shipComment” type=“xsd:string” substitutionGroup=“comment”/> <xsd:element name=“customerComment” type=“xsd:string” substitutionGroup=“comment”/>
Annotazione XSD fornisce un supporto proprietario per la documentazione dello schema Documentation contiene del testo destinato al lettore umano Appinfo contiene (meta)informazioni utilizzabili dell’applicazione <xsd:simpleType name=“tipoTesto”> <xsd:annotation> <xsd:documentation> questo elemento contiene del testo libero… </xsd:documentation> <xsd:appinfo> <hfp:hasFacet name=“length”/> </csd:appinfo> </xsd:annotation> … </xsd:simpleType>
Utilizzo degli XSD – 1 Il file XML può dichiarare lo schema a cui si riferisce sfruttando il namespace “http://www.w3.org/2001/XMLSchema-instance” Se lo schema non definisce un targetNamespace lo si può utilizzare per gli elementi non qualificati Se lo schema definisce un target occorre utilizzare il namespace corretto <?xml version=“1.0”?> <note xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:noNamespaceSchemaLocation=“”http://www.elet.polimi.it/note.xsd”> …</note> <?xml version=“1.0”?> <note:note xmlns:note=“http://www.elet.polimi.it/” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=“http://www.elet.polimi.it/note.xsd”> …</note:note>
Utilizzo degli XSD – 2 Se si utilizzano tipi derivati dove lo schema prevederebbe il tipo originale è necessario specificare il tipo (binding dinamico) tramite l’attributo xsi:type <note:testo xsi:type=“note:TipoTestoInternazionale” language=“IT”> … <note:estratto>estratto in lingua italiana</note:estratto> </note:testo>
Altre caratteristiche OO – 1 Elementi astratti: sono elementi che non verranno mai inclusi nell’XML, ma servono come base per gruppi di sostituzione Tipi astratti: richiedono l’uso di un sottotipo concreto (utilizzando xsi:type per segnalare il polimorfismo) <xsd:element name=“comment” type=“xsd:string” abstract=“true” /> <complexType name=“veicolo” abstract=“true”/> <complexType name=“auomobile”> <complexContent> <extension base=“veicoli:veicolo”/> </complexContent> </complexType> <element name=“trasporto” type=“veicoli:veicolo”> NO <trasporto/> SI <trasporto xsi:type=“automobile”/>
Altre caratteristiche OO – 2 Tipi e facet final: bloccano la ridefinizione nei sottotipi <redefine> permette di modificare una parte della definizione di uno schema. E’ sostanzialmente molto simile ad <include>, ma modifica lo schema importato