Przykład XSD
Ten rozdział pokaże, jak napisać schemat XML. Dowiesz się również, że schemat można napisać na różne sposoby.
Dokument XML
Rzućmy okiem na ten dokument XML o nazwie „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>
Powyższy dokument XML składa się z elementu głównego „shiporder”, który zawiera wymagany atrybut o nazwie „orderid”. Element „shiporder” zawiera trzy różne elementy podrzędne: „orderperson”, „shipto” i „item”. Element „item” pojawia się dwukrotnie i zawiera „title”, opcjonalny element „note”, element „ilość” i „cena”.
Powyższy wiersz: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" mówi parserowi XML, że ten dokument powinien zostać zweryfikowany względem schematu. Wiersz: xsi:noNamespaceSchemaLocation="shiporder.xsd" określa GDZIE znajduje się schemat (tutaj jest w tym samym folderze co "shiporder.xml").
Utwórz schemat XML
Teraz chcemy stworzyć schemat dla powyższego dokumentu XML.
Zaczynamy od otwarcia nowego pliku, który nazwiemy „shiporder.xsd”. Aby utworzyć schemat, moglibyśmy po prostu postępować zgodnie ze strukturą w dokumencie XML i zdefiniować każdy element, gdy go znajdziemy. Zaczniemy od standardowej deklaracji XML, po której nastąpi element xs:schema definiujący schemat:
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
...
</xs:schema>
W powyższym schemacie używamy standardowej przestrzeni nazw (xs), a identyfikator URI powiązany z tą przestrzenią nazw to definicja języka Schema, która ma standardową wartość http://www.w3.org/2001/XMLSchema.
Następnie musimy zdefiniować element „shiporder”. Ten element posiada atrybut i zawiera inne elementy, dlatego uważamy go za typ złożony. Elementy potomne elementu „shiporder” są otoczone elementem xs:sequence, który definiuje uporządkowaną sekwencję podelementów:
<xs:element name="shiporder">
<xs:complexType>
<xs:sequence>
...
</xs:sequence>
</xs:complexType>
</xs:element>
Następnie musimy zdefiniować element „orderperson” jako typ prosty (ponieważ nie zawiera żadnych atrybutów ani innych elementów). Typ (xs:string) jest poprzedzony prefiksem przestrzeni nazw skojarzonym ze schematem XML, który wskazuje predefiniowany typ danych schematu:
<xs:element name="orderperson" type="xs:string"/>
Następnie musimy zdefiniować dwa elementy, które są typu złożonego: „shipto” i „item”. Zaczynamy od zdefiniowania elementu „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>
Za pomocą schematów możemy zdefiniować liczbę możliwych wystąpień elementu z atrybutami maxOccurs i minOccurs. maxOccurs określa maksymalną liczbę wystąpień elementu, a minOccurs określa minimalną liczbę wystąpień elementu. Domyślna wartość zarówno maxOccurs, jak i minOccurs to 1!
Teraz możemy zdefiniować element "item". Ten element może pojawiać się wielokrotnie w elemencie „shiporder”. Jest to określane przez ustawienie atrybutu maxOccurs elementu „item” na „unbounded”, co oznacza, że może istnieć tyle wystąpień elementu „item”, ile życzy sobie autor. Zauważ, że element „note” jest opcjonalny. Określiliśmy to, ustawiając atrybut minOccurs na 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>
Możemy teraz zadeklarować atrybut elementu „shiporder”. Ponieważ jest to wymagany atrybut, określamy use="required".
Uwaga: Deklaracje atrybutów muszą być zawsze ostatnie:
<xs:attribute name="orderid" type="xs:string" use="required"/>
Oto pełna lista pliku schematu o nazwie „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>
Podziel schemat
Poprzednia metoda projektowania jest bardzo prosta, ale może być trudna do odczytania i utrzymania, gdy dokumenty są złożone.
Kolejna metoda projektowania polega na zdefiniowaniu najpierw wszystkich elementów i atrybutów, a następnie odwołaniu się do nich za pomocą atrybutu ref.
Oto nowy projekt pliku schematu ("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>
Korzystanie z nazwanych typów
Trzecia metoda projektowania definiuje klasy lub typy, które umożliwiają nam ponowne wykorzystanie definicji elementów. Odbywa się to poprzez nazywanie elementów simpleTypes i complexTypes, a następnie wskazywanie na nie poprzez atrybut type elementu.
Oto trzeci projekt pliku schematu ("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>
Element ograniczenia wskazuje, że typ danych pochodzi z typu danych przestrzeni nazw W3C XML Schema. Zatem poniższy fragment oznacza, że wartość elementu lub atrybutu musi być wartością ciągu:
<xs:restriction base="xs:string">
Element ograniczenia jest częściej używany do nakładania ograniczeń na elementy. Spójrz na następujące wiersze z powyższego schematu:
<xs:simpleType name="orderidtype">
<xs:restriction base="xs:string">
<xs:pattern value="[0-9]{6}"/>
</xs:restriction>
</xs:simpleType>
Oznacza to, że wartość elementu lub atrybutu musi być ciągiem, musi składać się dokładnie z sześciu znaków z rzędu, a te znaki muszą być liczbą od 0 do 9.