Copyright © 2006 Mihai Gabroveanu
Abstract
O XML Schema este un document bine format (de regula cu extensia .xsd) care defineste structura si tipul elementelor unui document XML in vederea valiadarii.
XML Schema a inceput ca o initiativa a companiei Microsoft. Intre timp insa, consortiul W3C a preluat aceasta initiativa si a dezvoltat un set mai larg de cerinte si caracteristici pentru documente ce descriu tipuri de documente. Acestea sunt reunite sub numele de Document Content Description, informatii despre acest proiect sunt disponibile la http://www.w3.org/TR/NOTE-dcd. In anul 2001 propunerea a devenit recomandare a W3C. Spre deosebire de (sau in plus fata de) DTD-uri, XML schema permite definirea regulilor si relatiilor intre elemente si attribute folosind un fisier XML (cu alte cuvinte, o schema XML este descrisa intr-un fisier XML). In plus, se adauga suport pentru spatii de nume (namespaces), tipuri de date si caracteristici mai avansate cum ar fi constrangerile (constraints).
O XML Schema:
defineste elementele care pot sa apara intr-un document
defineste atributele pe care pot sa le aiba elementele dintr-un document
defineste care elemente au copii si care sunt acestia
defineste ordinea copiilor unui element
defineste numarul de copii
defineste daca un element este vid sau poate contine un text
defineste tipurile elementelor si atributelor
defineste valorile implicite si fixe ale elementelor si atributelor
Spre deosebire de referirea la un DTD intr-un document XML care se facea inainte de elementul radacina:
<?xml version="1.0?> <!DOCTYPE elementRadacina SYSTEM "url"> <elementRadacina> ... </elementRadacina>
Referirea la o XML Schema intr-un document XML se face in cadrul elementului radacina:
<?xml version="1.0"?>
<elementRadacina xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
"
xsi:noNamespaceSchemaLocation="url.xsd">
...
</elementRadacina>
unde:
Exemplu:
<?xml version="1.0">
<CARTE xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
"
xsi:noNamespaceSchemaLocation="CARTE.xsd" >
<TITLU>XML Bible</TITLU>
<AUTOR>Elliotte Rusty Harold</AUTOR>
<EDITURA> IDG Books Worldwide</EDITURA>
<AN_APARITIE>2002</AN_APARITIE>
</CARTE>
Un fisier XML Schema utilizeaza sintaxa XML pentru definirea structurii si tipurilor elementelor unui document XML in vederea validarii. Un fisier XML Schema are extensia .xsd
si este un fisier XML ce are ca radacina <schema>. Forma generala a unui astfel de document este urmatoarea:
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://inf.ucv.ro" xmlns="http://inf.ucv.ro" elementFormDefault="qualified"> ... ... </xs:schema>
unde:
Exemplu:
Un element se numeste element simplu daca:
contine numai informatie text (date caracter)
nu are atribute
nu contine alte atribute
nu este vid
Totusi informatia text continuta de element poate sa fie de diferite tipuri. Ea poate sa fie de unul dintre tipurile predefinite in XML Schema (boolean, string, date, etc.), sau poate fi de un tip definit de noi. De asemenea se pot adauga restricii (fatete) asupra tipurilor de date pentru a stabili limitele, sau putem sa stabilim un patern peste care trebuie sa se potriveasca.
Sintaxa definiri unui element simplu este urmatoarea:
<xs:element name="nume" type="tip"/>
unde:
nume este numele elementului
tip este tipul elementului
In XML Schema sunt predefinite urmatoarele tipuri:
xs:string
xs:decimal
xs:integer
xs:boolean
xs:date
xs:time
Exemplu: sa consideram urmatoarele elemente XML:
<NUME>Popescu Maria</NUME> <VARSTA>21</VARSTA> <DATA_NASTERII>1985-09-23</DATA_NASTERII>
atunci definitiile corespunzatoare ale acestor elemente simple in XML Schema sunt:
<xs:element name="NUME" type="xs:string"/> <xs:element name="VARSTA" type="xs:integer"/> <xs:element name="DATA_NASTERII" type="xs:date"/>
Elementele simple pot avea in anumite situatii valori implicite SAU o valore fixa. Sintaxa declararii acestora este:
<xs:element name="nume" type="tip" default="valoare-implicita"/>
si respectiv:
<xs:element name="nume" type="tip" fixed="valoare-fixa"/>
O valoare implicita este atribuita unui element atunci cand nu este specificata nici o alta valoare valoare. In exemplul urmator valoarea implicita este "alb-negru":
<xs:element name="TIP-IMPRIMANTA" type="xs:string" default="alb-negru"/>
O valoare fixa este atribuita de asemenea automat unui element si nu putem specifica nici o alta valoare in afara de cea specificata. In exemplul urmator valoarea fixa este "romana":
<xs:element name="CETATENIA" type="xs:string" fixed="romana"/>
Elementele simple nu pot avea atribute. Daca un element are cel putin un atribut atunci este considerat de element de tip complex. Totusi, atributul insusi este declarat intotdeauna ca un tip simplu. Sintaxa de definire a unui atribut este urmatoarea:
<xs:attribute name="nume" type="tip" />
unde:
nume este numele atributului
tip este tipul atributului identic cu cel de la definirea elementelor simple
Exemplu: daca cosideram urmatorul element cu un atribut:
<PERSOANA sex="masculin">Garcea Ion</PERSOANA>
atunci definitia atributului cnp este urmatoarea:
<xs:attribute name="sex" type="xs:string"/>
Sintaxa XML Schema pentru definirea atributelor permite de asemenea definirea de valori implicite (default) pentru atribute SAU atribute cu valori fixe. Sintaxa definirii acestora este urmatoarea:
<xs:attribute name="nume" type="tip" default="valoare-implicita" />
si respectiv:
<xs:attribute name="nume" type="tip" fixed="valoare-fixa" />
De asemenea sintaxa permite stabilirea faptului ca atributul este optional sau obligatoriu. Sintaxa definirii acestora este urmatoarea:
<xs:attribute name="nume" type="tip" use="optional" />
si respectiv:
<xs:attribute name="nume" type="tip" use="required" />
Atunci cand definim tipul pentru un element simplu sau pentru un atribut, automat sunt impuse asupa continutului o serie de conditii. Astfel daca pentru un element am stabilit tipul xs:integer si contine o valoare de genul "21-07-2006" documentul respectiv nu va fi valid. Avem posibilitatea sa definim si alte restrictii proprii asupa continutului elementului sau atributului. Aceste restrictii se numesc fatete.
Sintaxa generala a definirii acestor restrictii este urmatoarea:
<xs:element name="nume"> (sau xs:attribute) <xs:simpleType> <xs:restriction base="tip"> ... restrictii ... </xs:restriction> </xs:simpleType> </xs:element>
Exemplu:
<xs:element name="nota"> <xs:simpleType> <xs:restriction base="xs:integer"> <xs:minInclusive value="1"> <xs:maxInclusive value="10"> </xs:restriction> </xs:simpleType> </xs:element>
Asupra valorilor de tip numeric putem definii urmatoarele tipuri de restrictii:
minInclusive - numarul trebuie sa fie mai mare sau egal decat o valoare data
minExclusive - numarul trebuie sa fie mai mare strict decat o valoare data
maxInclusive - numarul trebuie sa fie mai mic sau egal decat o valoare data
maxExclusive - numarul trebuie sa fie mai mic strict decat o valoare data
totalDigits - numarul de cifre ale numarului trebuie sa aiba exact o valoare data
fractionDigits - numarul de cifre de dupa virgula nu trebuie sa depaseasca o valoare data
Asupra valorilor de tip string putem definii urmatoarele tipuri de restrictii:
length - lungimea sirului trebuie sa fie egala cu o valoare data
minLength - lungimea sirului trebuie sa fie mai mare sau egala cu o valoare data
maxLength - lungimea sirului trebuie sa fie mai mica sau egala cu o valoare data
pattern - sirul trebuie sa se potriveasca cu e expresie regulata data
whiteSpace - nu este chiar o restrictie, ea spune cum sa trateze spatiile albe (white spaces):
value="preserve" - se pastreaza toate spatiile albe
value="replace" - toate spatiile albe sunt inlocuite cu spatii
value="collapse" - toate spatiile albe sunt comasate la un singur spatiu
Exemplu: Daca presupunem ca elementul INITIALE este format din exact 3 caractere toate litere mari atunci definirea elementului este urmatoarea:
<xs:element name="INITIALE"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:pattern value="[A-Z][A-Z][A-Z]"/> </xs:restriction> </xs:simpleType> </xs:element>
Putem impune ca valoarea unui element sau atribut sa ia numai o multime de valori. De exemplu daca consideram ca elementul ANOTIMP poate lua ca valori numai: primavara, vara, toamna si iarna atunci definitia elementului este urmatoarea:
<xs:element name="ANOTIMP"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:enumeration value="primavara"/> <xs:enumeration value="vara"/> <xs:enumeration value="toamna"/> <xs:enumeration value="iarna"/> </xs:restriction> </xs:simpleType> </xs:element>
Un element se numeste element complex daca contine alte element si/sau atribute. De asemenea elementele vide sunt considerate elemente complexe. Sintaxa definirii unui element complex este urmatoarea:
<xs:element name="nume"> <xs:complexType> ... descrierea tipului complex ... </xs:complexType> </xs:element>
Exemplu:
<xs:element name="PERSOANA"> <xs:complexType> <xs:sequence> <xs:element name="NUME" type="xs:string"/> <xs:element name="PRENUME" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element>
<xs:sequence> spune ca elementele NUME si PRENUME trebuie sa apara in acesta ordine.
Paradoxal elementele vide sunt de tip complex.
Sa consideram urmatorul element:
<PRODUS cod="1345" />
Definirea schemei pentru acesta arata astfel:
<xs:element name="PRODUS"> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:integer"> <xs:attribute name="cod" type="xs:positiveInteger"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element>
In exemplul anterior, am definit un complexType avand complexContent, adica numai elemente. Elementul complexContent semnaleaza ca intentionam sa restrictionam sau sa extindem un tip complex. Restrictia defineste un atribut cod ce poate lua numai valori pozitive.
Putem sa definim schema si astfel:
<xs:element name="PRODUS"> <xs:complexType> <xs:attribute name="cod" type="xs:positiveInteger"/> </xs:complexType> </xs:element>
Elementele declarate la nivele superioare ale unei <schema> sunt disponibile pentru restul schemei. Elementele declarate intr-un xs:complexType sunt locale in acel tip si nu pot fi referite la un nivel superior. Astfel in exemplul anterior elementele NUME si PRENUME sunt locale in cadrul elementului PERSOANA.
Unui tip complex ii putem asigna un nume astfel:
<xs:complexType name="nume-tip">
....
</xs:complexType>
Apoi ne putem referii la el printr-o constructie de foma:
<xs:element name="nume" type="nume-tip-declarat"/>
Exemplu:
<xs:complexType name="PERSOANA"> <xs:sequence> <xs:element name="NUME" type="xs:string"/> <xs:element name="PRENUME" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:element name="STUDENT" type="PERSOANA"/> <xs:element name="PROFESOR" type="PERSOANA"/>
Nu putem utiliza o referinta la un tip daca el este local unui alt tip!
Indicatori de oridine sunt utilizati pentru a defini ce elementele pot sa apara si in ce ordine.
Am vazut deja cum se declara in cadrul unui tip complex elementele ce trebuie sa apara intr-o anumita ordine:
<xs:element name="PERSOANA"> <xs:complexType> <xs:sequence> <xs:element name="NUME" type="xs:string"/> <xs:element name="PRENUME" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element>
Pentru a declara o multimea de elemente ce trebuie sa apara intr-un tip complex in care ordinea nu conteaza vom utiliza constructia xs:all:
Exemplu: Daca elementele NUME si PRENUME trebuie sa apara in elementul PERSOANA insa ordinea nu conteaza, atunci avem:
<xs:element name="PERSOANA"> <xs:complexType> <xs:all> <xs:element name="NUME" type="xs:string"/> <xs:element name="PRENUME" type="xs:string"/> </xs:all> </xs:complexType> </xs:element>
Indicatorul xs:choice permite definirea de tipuri complexe in care unul din elementele dintr-o multime poate sa apara:
<xs:element name="CARTE"> <xs:complexType> <xs:choice> <xs:element name="AUTOR" type="persoana"/> <xs:element name="EDITOR" type="persoana"/> </xs:choice> </xs:complexType> </xs:element>
Indicatorii de aparitie sunt utilizati pentru a defini de cate ori poate sa apara un element.
Indicator maxOccurs specifica numarul maxim de aparitii pentru un element:
<xs:element name="PERSOANA"> <xs:complexType> <xs:sequence> <xs:element name="NUME" type="xs:string"/> <xs:element name="NUME-COPIL" type="xs:string" maxOccurs="5"/> </xs:sequence> </xs:complexType> </xs:element>
In exemplu anterior elementul NUME-COPIL trebuie sa apara cel putin odata (valoarea implicita pentru minOccurs este 1 implicit) si de maxim 5 ori in secventa ce descrie elementul PERSOANA.
Indicator minOccurs specifica numarul minim de aparitii pentru un element:
<xs:element name="PERSOANA"> <xs:complexType> <xs:sequence> <xs:element name="NUME" type="xs:string"/> <xs:element name="NUME-COPIL" type="xs:string" minOccurs="0" maxOccurs="5"/> </xs:sequence> </xs:complexType> </xs:element>
In exemplu anterior elementul NUME-COPIL poate sa nu apara deloc sau de maxim 5 ori in secventa ce descrie elementul PERSOANA.
Pentru toate tipurile de indicatori de grupare sau ordine (any, all, choice, sequence, group name, and group reference) valoarea implicita pentru maxOccurs and minOccurs este 1!
Sunt utilizati pentru multimi de elemente inrudite. Sintaxa definirii grupurilor de elemente este urmatoarea:
<xs:group name="nume-grup">
...
</xs:group>
in cadrul unui grup putem defini elemente all, choice, or sequence.
Exemplu: Sa presupunem ca dorim sa definim un grup cu nume "GRUP-PERSOANA", ce defineste grupul de elemente ce trebuie sa apara exact intr-o ordine specificata. Atunci avem:
<xs:group name="GRUP-PERSOANA"> <xs:sequence> <xs:element name="NUME" type="xs:string"/> <xs:element name="PRENUME" type="xs:string"/> <xs:element name="DATA-NASTERE" type="xs:date"/> </xs:sequence> </xs:group>
Ulterior ne putem referi la acel grup in cadrul altui grup sau in cadrul definirii tip complex astfel:
<xs:element name="PERSOANA" type="INFO-PERSOANA"/> <xs:complexType name="INFO-PERSOANA"> <xs:sequence> <xs:group ref="GRUP-PERSOANA"/> <xs:element name="TARA" type="xs:string"/> </xs:sequence> </xs:complexType>
Sintaxa definirii grupurilor de atribute este urmatoarea:
<xs:attributeGroup name="nume-grup">
...
</xs:attributeGroup>
Exemplu: Sa presupunem ca dorim sa definim un grup cu nume "GRUP-PERSOANA", ce defineste grupul de elemente ce trebuie sa apara exact intr-o ordine specificata. Atunci avem:
<xs:attributeGroup name="GRUP-PERSOANA"> <xs:attribute name="nume" type="xs:string"/> <xs:attribute name="prenume" type="xs:string"/> <xs:attribute name="data-nasterii" type="xs:date"/> </xs:attributeGroup>
Ulterior ne putem referi la acel grup in cadrul altui grup sau in cadrul definirii tip complex astfel:
<xs:element name="PERSOANA" type="INFO-PERSOANA"/> <xs:complexType name="INFO-PERSOANA"> <xs:attributeGroup ref="GRUP-PERSOANA"> </xs:complexType>
Sa consideram urmatorul document XML ce isi propune sa reprezinte un ordin de plata:
<?xml version="1.0" encoding="ISO-8859-1"?> <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>
O schema XML atasata acestui document ar putea arata astfel:
<?xml version="1.0" encoding="ISO-8859-1" ?> <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>
Schema prezentata anterior este relativ simpla insa poate sa devina dificil de inteles in conditiile in care documentul ar fi mai complex.
In continuare este prezentata o versiune imbunatatita bazata pe urmatorul principiu: definim mai intai elemente si atributele, apoi le referim utilizand atributul ref.
<?xml version="1.0" encoding="ISO-8859-1" ?> <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>
Putem sa rafinam si mai mult designul schemei asignand nume tipurilor:
<?xml version="1.0" encoding="ISO-8859-1" ?> <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>
XML Schema Part 0: Primer Second Edition W3C Recommendation 28 October 2004, David C. Fallside, Priscilla Walmsley
XML Schema Part 1: Structures Second Edition W3C Recommendation 28 October 2004, Henry S. Thompson, David Beech, Murray Maloney, Noah Mendelsohn
XML Schema Part 2: Datatypes Second Edition W3C Recommendation 28 October 2004, Paul V. Biron, Kaiser Permanente, Ashok Malhotra
Elliotte Rusty Harold, XML Bible. IDG Books Worldwide, Inc, 919 E. Hillsdale Blvd., Suite 400, Foster City, CA 94404
http://www.w3schools.com/schema/ XML Schema Tutorial