Rozdział 3.
Schematy XML
Strukturę dokumentu można opisywać na dwa sposoby: można użyć DTD - Definicji typu dokumentu - lub schematu XML. Metodą starszą i szerzej przyjętą są DTD. W tej książce nie są one omawiane, gdyż były omawiane już wielokrotnie w innych pozycjach, na przykład w wydanej niedawno książce „XML. Księga eksperta”. Zresztą W3C usłyszało o DTD wiele niechętnych opinii, a to głównie z uwagi na ich złożoność; użytkownicy domagali się jakiegoś prostszego standardu opisu struktury dokumentu. W związku z tym w W3C powstał zespół odpowiedzialny za znalezienie rozwiązania - ale stworzone rozwiązanie okazało się być znacznie bardziej skomplikowane niż jakiekolwiek DTD: są to Schematy XML --> .[Author:T]
Z drugiej strony schematy XML są narzędziem znacznie potężniejszym i bardziej precyzyjnym od DTD. Pozwalają nie tylko opisać składnię dokumentu, tak jak DTD, ale pozwalają określić typy danych w treści elementów, umożliwiają dziedziczenie składni po innych schematach, wstawianie komentarzy, używanie schematów posługujących się wieloma przestrzeniami nazw, tworzenie prostych i złożonych typów danych, określanie minimalnej i maksymalnej liczby wystąpień elementu, tworzenie typów w postac i list, tworzenie grup atrybutów, ograniczanie zakresu informacji, które inne schematy mogą dziedziczyć po danym, łączenie wielu schematów w całość, wymuszanie niepowtarzalności wartości atrybutów i tak dalej.
Obecnie specyfikacja schematów XML ma status szkicu roboczego, co oznacza, że zapewne zanim stanie się oficjalną rekomendacją, jeszcze się zmieni. Specyfikacja znajduje się w trzech dokumentach:
www.w3.org/TR/xmlschema-0/. Część wstępna, zawiera wprowadzenie do schematów XML.
www.w3.org/TR/xmlschema-1/. Struktury schematów XML, formalny opis tworzenia schematów.
www.w3.org/TR/xmlschema-2/. Typy danych schematów XML, pełny opis typów danych, jakie można stosować w schematach.
Grupa robocza pracująca nad schematami stanęła przed kilkoma wyzwaniami, w tym między innymi: obsługą przestrzeni nazw podczas walidacji dokumentów, przedstawieniem koncepcji obsługi typów danych i nakładanie na dane ograniczeń, umożliwianiem i blokowaniem dziedziczenia pomiędzy schematami, stworzeniem podstawowych typów danych.
Istnieje już nieco oprogramowania obsługującego schematy XML. W3C udostępniało pod adresem http://cgi.w3.org/cgi-bin/xmlschema-check wczesną wersję kontrolera schematów, ale teraz pod adresem www.w3.org/2000/06/webdata/xsv (zapewne tymczasowym) znajduje się nowy kontroler schematów. Częściową obsługę schematów zawiera parser Xerces XML oferowany przez firmę Apache, więcej szczegółów pod adresem http://xml.apache.org/xerces-j/. Warto też zajrzeć na stronę Oracle, http://technet.oracle.com/tech/xml/schema_java/index.htm oraz na stronę XML Spy, http://new.xmlspy.com/features_schema.html. Jeszcze więcej dodatkowego oprogramowania do obsługi schematów (w tym narzędzia do przekształcania DTD na schematy) znajdziesz pod adresem www.w3.org/XML/Schema.html.
Jednym z pierwszych rzeczników schematów XML był Microsoft. W dokumentacji tej firmy często opisywano DTD jako zbyt złożone i twierdzono, że schematy problem ten rozwiążą. W końcu jednak okazało się, że jest inaczej, a implementacja schematów XML w Internet Explorerze była przestarzała wkrótce po jej przedstawieniu.
Schematy XML w Internet Explorerze
Podobnie jak wielu innych wytwórców oprogramowania, tak i Microsoft zaczął pracę już na dość wczesnych wersjach specyfikacji XML, która szybko się zmieniała. Schematy XML Microsoftu oparte zostały na dokumentach XML-Data Note (www.w3.org/TR/1998/NOTE-XML-data-0105/) oraz Document Content Description (DCD, www.w3.org/TR/NOTE-dcd) i obecnie są już całkowicie nieaktualne.
W tym rozdziale przyjrzymy się schematom w ich jedynej znanej autorowi implementacji, w Internet Explorerze. Potem zajmiemy się już obowiązującą obecnie specyfikacją i przyjrzymy się, jak jej można użyć.
Dokumentację schematów XML w ujęciu Microsoftu znajdziesz pod adresem http://msdn.microsoft.com/xml/reference/schema/start.asp. Przy badaniu schematów posłużymy się przykładowym dokumentem XML opisującym zespół programistów, elementem głównym będzie ZESPÓŁ_PROGRAMISTÓW:
<?xml version="1.0" encoding="iso-8859-2"?>
<ZESPÓŁ_PROGRAMISTÓW>
<PROGRAMISTA>Fred Samson</PROGRAMISTA>
<PROGRAMISTA>Edward Fredericks</PROGRAMISTA>
<OPIS>Zespół programistów XML</OPIS>
</ZESPÓŁ_PROGRAMISTÓW>
Jak powiązać ten dokument ze schematem w Internet Explorerze? Robi się to określając domyślną przestrzeń nazw dla dokumentu przy pomocy atrybutu xmlns w elemencie głównym i poprzedzając nazwę pliku ze schematem napisem x-schema:, na przykład tak:
<?xml version="1.0" encoding="iso-8859-2"?>
<ZESPÓŁ_PROGRAMISTÓW xmlns="x-schema:schema1.xml">
<PROGRAMISTA>Fred Samson</PROGRAMISTA>
<PROGRAMISTA>Edward Fredericks</PROGRAMISTA>
<OPIS>Zespół programistów XML</OPIS>
</ZESPÓŁ_PROGRAMISTÓW>
Plik ze schematem nazywał się będzie zatem schema1.xml (rozszerzenie nie ma większego znaczenia), teraz wystarczy tylko stworzyć sam plik. Robi się to umieszczając element schema, ot tak:
<schema>
.
.
.
</schema>
Za pomocą atrybutu name schemat można nazwać:
<schema name="schema1">
.
.
.
</schema>
Jedną z zalet schematów XML jest to, że umożliwiają one wskazanie używanych typów danych, jednak jako że typy te w chwili implementacji przez Microsoft schematów nie były jeszcze w pełni określone, Microsoft zastosował własne typy. Aby stworzyć schemat przeznaczony dla Internet Explorera, przygotuj domyślną przestrzeń nazw, urn:schemas-microsoft-com:xml-data oraz przypisz przestrzeni nazw typów danych, urn:schemas-microsoft-com:datatypes przedrostek dt:
<schema name="schema1"
xmlns="urn:schemas-microsoft-com:xml-data"
xmlns:dt="urn:schemas-microsoft-com:datatypes">
.
.
.
</schema>
Teraz już typy danych obsługiwane przez Internet Explorer dostępne są z przedrostkiem dt. Typy te zestawiono w tabeli 5.1. Więcej informacji na ich temat znajdziesz pod adresem http://msdn.microsoft.com/xml/reference/schema/datatypes.asp.
Tabela 3.1.
Typy danych schematów XML Microsoftu
Typ |
Opis |
bin.base64 |
Zakodowany w base-64 obiekt binarny. |
bin.hex |
Cyfry szesnastkowe. |
boolean |
Wartość 0 lub 1. |
char |
Jednoznakowy napis. |
date |
Data (w formacie ISO 8601 bez czasu, na przykład 2001-10-15). |
dateTime |
Data i czas (w formacie ISO 8601 z opcjonalną częścią czasu, na przykład 2001-10-15T09:41:33). |
dateTime.tz |
Data i czas (w formacie ISO 8601 z opcjonalną częścią czasu i strefą czasową, na przykład 2001-10-15T09:41:33-08:00). |
fixed.14.4 |
Format identyczny jak number, ale na lewo od kropki dziesiętnej znajdować się może nie więcej niż 14 cyfr, zaś na prawo co najwyżej 4 cyfry. |
float |
Liczba zmiennoprzecinkowa. |
int |
Liczba całkowita. |
number |
Liczba bez ograniczenia na liczbę cyfr. Wartość może mieć znak, część ułamkową oraz wykładnik. |
time |
Czas w formacie ISO 8601, bez daty ani strefy czasowej. |
time.tz |
Czas w formacie ISO 8601 bez daty, ale z opcjonalną strefą czasową. |
i1 |
Liczba całkowita zapisana na jednym bajcie. |
i2 |
Liczba całkowita zapisana w jednym słowie. |
i4 |
Liczba całkowita zapisana na czterech bajtach. |
r4 |
Liczba rzeczywista o dokładności 7 cyfr. |
r8 |
Liczba rzeczywista o dokładności 15 cyfr. |
ui1 |
Liczba całkowita bez znaku zapisana na jednym bajcie. |
ui2 |
Liczba całkowita bez znaku zapisana w jednym słowie. |
ui4 |
Liczba całkowita bez znaku zapisana na czterech bajtach. |
uri |
Uniwersalny identyfikator zasobu (URI). |
uuid |
Szesnastkowe cyfry reprezentujące oktety. |
Do opisania składni elementu w schemacie w Internet Explorerze używa się elementu elementtype. Zaczniemy od poinformowania, że elementy PROGRAMISTA oraz OPIS zawierać mogą jedynie tekst i że ich model zawartości jest zamknięty, co oznacza, że nie mogą zawierać żadnej innej zawartości poza wskazaną (w opisywanej odmianie schematów pozostawienie otwartego modelu zawartości pozwala elementowi zawierać treści inne niż wskazane):
<schema name="schema1"
xmlns="urn:schemas-microsoft-com:xml-data"
xmlns:dt="urn:schemas-microsoft-com:datatypes">
<elementtype name="PROGRAMISTA" content="textOnly" model="closed"/>
<elementtype name="OPIS" content="textOnly" model="closed"/>
.
.
.
--> </schema>[Author:T]
Jeśli chcesz wskazać typ elementu, możesz użyć atrybutu dt:type z jedną z wartości podanych w tabeli 3.1:
<schema name="schema1"
xmlns="urn:schemas-microsoft-com:xml-data"
xmlns:dt="urn:schemas-microsoft-com:datatypes">
<elementtype name="PROGRAMISTA" content="textOnly" model="closed"/>
<elementtype name="OPIS" content="textOnly" model="closed"/>
<elementtype name="licznik" dt:type="int"/>
.
.
.
</schema>
--> Niestety, Internet Explorer nie obsługuje jeszcze kontroli typów danych podawanych w schematach, typów tych można jednak użyć bezpośrednio w dokumentach XML:[Author:T]
<dokument xmlns:dt="urn:schemas-microsoft-com/:datatypes"><dt:int>8</dt:int></dokument>
Teraz do naszego schematu wstawiamy element ZESPÓŁ_PROGRAMISTÓW. Element ten może zawierać elementy PROGRAMISTA oraz OPIS i może zawierać tylko elementy, nie może zawierać zwykłych danych tekstowych. Aby to zapisać, stosuje się wartość eltOnly atrybutu content w elemencie elementtype. Przy okazji stosując atrybuty minOccurs i maxOccurs nakazujemy, aby element PROGRAMISTA pojawił się co najmniej raz, a element OPIS - dokładnie raz:
<schema name="schema1"
xmlns="urn:schemas-microsoft-com:xml-data"
xmlns:dt="urn:schemas-microsoft-com:datatypes">
<elementtype name="PROGRAMISTA" content="textOnly" model="closed"/>
<elementtype name="OPIS" content="textOnly" model="closed"/>
<elementtype name="ZESPÓŁ_PROGRAMISTÓW" content="eltOnly" model="closed">
<element type="PROGRAMISTA" minOccurs="1" maxOccurs="*"/>
<element type="OPIS" minOccurs="1" maxOccurs="1"/>
</elementtype>
</schema>
I tak właśnie schematy XML wyglądają w Internet Explorerze. Nie warto dalej tego przykładu ciągnąć, gdyż te schematy odchodzą już w cień jako niezgodne z obowiązującą specyfikacją schematów XML, więc Microsoft będzie musiał tę implementację zmienić.
Z tego też powodu w dalszej części rozdziału przyjrzymy się, jak W3C przedstawia schematy. Niestety, nie istnieje jeszcze żadne oprogramowanie je obsługujące, ale z pewnością takowe się pojawi. Zapewne w końcu, kiedy schematy zostaną opublikowane jako oficjalna rekomendacja, będą obsługiwane także w Internet Explorerze, zatem to, co będzie opisywane teraz, będzie obowiązywało w przyszłości wszystkich, z Internet Explorerem włącznie.
Schematy XML zgodnie z W3C
Większość tego rozdziału oparta będzie na przykładowym dokumencie książka.xml, tworzyć będziemy dla niego schemat w pliku książka.xsd (.xsd to standardowe rozszerzenie plików ze schematami używane przez W3C). Przykład ten dotyczy książek pożyczonych przez jedną osobę, Douga Glassa, Britcie Regensburg. W dokumencie zarejestrowano nazwiska i adresy oraz dane o książkach: tytuły, daty wydania, wartość oraz maksymalny termin wypożyczenia w dniach. Oto postać pliku książka.xml:
<?xml version="1.0" encoding="iso-8859-2"?>
<transakcja dataWypożyczenia="2001-10-15">
<właściciel telefon="607.555.2222">
<nazwisko>Doug Glass</nazwisko>
<ulica>416 Disk Drive</ulica>
<miasto>Medfield</miasto>
<stan>MA</stan>
</właściciel>
<wypożyczający telefon="310.555.1111">
<nazwisko>Britta Regensburg</nazwisko>
<ulica>219 Union Drive</ulica>
<miasto>Medfield</miasto>
<stan>CA</stan>
</wypożyczający>
<uwagi>Właściciel żąda zwrotu książki w ciągu dwóch tygodni!</uwagi>
<książki>
<książka IDksiążki="123-4567-890">
<tytuł>Trzęsienia ziemi na dzień dobry</tytuł>
<dataWydania>2001-10-20</dataWydania>
<wartość>15.95</wartość>
<terminMaksymalny>14</terminMaksymalny>
</książka>
<książka IDksiążki="123-4567-891">
<tytuł>Lawiny koło obiadu</tytuł>
<dataWydania>2001-10-21</dataWydania>
<wartość>19.99</wartość>
<terminMaksymalny>14</terminMaksymalny>
</książka>
<książka IDksiążki="123-4567-892">
<tytuł>Deszcz meteorów pod wieczór</tytuł>
<dataWydania>2001-10-22</dataWydania>
<wartość>11.95</wartość>
<terminMaksymalny>14</terminMaksymalny>
</książka>
<książka IDksiążki="123-4567-893">
<tytuł>Skakanie po wulkanach</tytuł>
<dataWydania>201-10-23</dataWydania>
<wartość>17.99</wartość>
<terminMaksymalny>14</terminMaksymalny>
</książka>
</książki>
</transakcja>
Elementem głównym jest transakcja, w nim są elementy właściciel, wypożyczający i książki, i tak dalej.
W rozumieniu schematów XML elementy zawierające podelementy lub atrybuty nazywane są typami złożonymi. Elementy zawierające jedynie dane proste, takie jak liczby, napisy czy daty są typu prostego. Atrybuty zawsze są typu prostego, gdyż ich wartości nie mogą zawierać żadnej struktury wewnętrznej. Jeśli na dokument spojrzysz jako na drzewko, typy proste nie mają podwęzłów, natomiast typy złożone mogą je mieć.
Rozróżnienie między typami prostymi i złożonymi jest istotne, gdyż typy proste i typy złożone inaczej się deklaruje. Typy złożone deklaruje autor schematu, natomiast specyfikacja zawiera już wiele gotowych typów prostych. Tym niemniej można jednak samemu tworzyć nowe typy proste.
Kolejna istotna rzecz: w pokazanym dokumencie książka.xml nigdzie nie jest zaznaczone, jaki schemat ma być użyty do walidacji (w przypadku DTD znacznik <!DOCTYPE> wskazuje zewnętrzną definicję). W3C zakłada, że procesor XML będzie w stanie odnaleźć schemat nawet bez umieszczania w tym dokumencie jakiejkolwiek informacji. W tej chwili nie jest do końca jasne, jak to ma działać, choć W3C chyba planuje powiązać dokument z jego schematem za pośrednictwem przestrzeni nazw, co zresztą widzieliśmy w poprzednim dokumencie przykładowym przeznaczonym dla Internet Explorera:
<?xml version="1.0" encoding="iso-8859-2"?>
<ZESPÓŁ_PROGRAMISTÓW xmlns="x-schema:schema1.xml">
<PROGRAMISTA>Fred Samson</PROGRAMISTA>
<PROGRAMISTA>Edward Fredericks</PROGRAMISTA>
<OPIS>Zespół programistów XML</OPIS>
</ZESPÓŁ_PROGRAMISTÓW>
Do procesora należy odszukanie schematu na podstawie deklaracji przestrzeni nazw. W przypadku Explorera nie jest to specjalny problem, ponieważ program ten „wie”, że jeśli przestrzeń nazw zaczyna się od x-schema, to jest to schemat. Jednak w przypadku ogólnym konieczne będzie deklarowanie dla dokumentu przestrzeni nazw odnoszącej się do schematu, ot choćby tak:
<?xml version="1.0" encoding="iso-8859-2"?>
<transakcja dataWypożyczenia="2001-10-15"
xmlns="http://www.starpowder.com/">
<właściciel telefon="607.555.2222">
<nazwisko>Doug Glass</nazwisko>
<ulica>416 Disk Drive</ulica>
<miasto>Medfield</miasto>
<stan>MA</stan>
</właściciel>
.
.
.
Teraz zadaniem procesora XML będzie odnalezienie na podstawie takiego opisu schematu, w którym deklaruje się docelową przestrzeń nazw. Kiedy procesor XML odnajdzie schemat i potwierdzi identyczność przestrzeni docelowej schematu i dokumentu, może rozpocząć walidację. Z dalszymi wyjaśnieniami dotyczącymi tego procesu trzeba będzie poczekać na spopularyzowanie się schematów XML.
Przejdźmy do schematu odpowiadającego naszemu dokumentowi - zapisany jest on w pliku książka.xsd, przedrostek xsd: jest standardowo używany przez W3C do wskazania elementów należących do przestrzeni nazw schematów. Później zajmiemy się też sposobem pominięcia tego przedrostka, zwykle jednak elementy schematów faktycznie poprzedza się przedrostkiem xsd:, aby elementy te nie wchodziły w konflikt z innymi elementami używanymi lokalnie. Zwróć uwagę na to, że książka.xsd - podobnie jak wszystkie inne schematy - są poprawnie sformułowanymi dokumentami XML:
<xsd:schema xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<xsd:annotation>
<xsd:documentation>
Schemat opisujący wypożyczenia książek.
</xsd:documentation>
</xsd:annotation>
<xsd:element name="transakcja" type="typTransakcja"/>
<xsd:complexType name="typTransakcja">
<xsd:element name="właściciel" type="adres"/>
<xsd:element name="wypożyczający" type="adres"/>
<xsd:element ref="uwagi" minOccurs="0"/>
<xsd:element name="książki" type="typKsiążka"/>
<xsd:attribute name="dataWypożyczenia" type="xsd:date"/>
</xsd:complexType>
<xsd:element name="uwagi" type="xsd:string"/>
<xsd:complexType name="adres">
<xsd:element name="nazwisko" type="xsd:string"/>
<xsd:element name="ulica" type="xsd:string"/>
<xsd:element name="miasto" type="xsd:string"/>
<xsd:element name="stan" type="xsd:string"/>
<xsd:attribute name="telefon" type="xsd:string"
use="optional"/>
</xsd:complexType>
<xsd:complexType name="typKsiążka">
<xsd:element name="książka" minOccurs="0" maxOccurs="10">
<xsd:complexType>
<xsd:element name="tytuł" type="xsd:string"/>
<xsd:element name="dataWydania" type="xsd:date" minOccurs='0'/>
<xsd:element name="wartość" type="xsd:decimal"/>
<xsd:element name="terminMaksymalny">
<xsd:simpleType base="xsd:integer">
<xsd:maxExclusive value="14"/>
</xsd:simpleType>
</xsd:element>
<xsd:attribute name="IDksiążki" type="IDKatalogu"/>
</xsd:complexType>
</xsd:element>
</xsd:complexType>
<xsd:simpleType name="IDKatalogu" base="xsd:string">
<xsd:pattern value="\d{3}-\d{4}-\d{3}"/>
</xsd:simpleType>
</xsd:schema>
W dalszej części tego rozdziału będziemy analizować poszczególne części tego schematu, ale strukturę już teraz mniej więcej można rozpoznać. Zaczynamy od definicji przestrzeni nazw http://www.w3.org/1999/XMLSchema, do przestrzeni tej należą elementy takie jak xsd:element (przedrostek xsd: można by pominąć, ale zwykle się go jednak podaje). Elementy deklarowane są w elemencie xsd:element, atrybuty w elemencie xsd:attribute. Typ elementów i atrybutów określa się podczas ich definiowania. Nowe typy tworzy się za pomocą elementów xsd:complexType i xsd:simpleType, komentarze dodaje się w elemencie xsd:annotation i tak dalej.
W naszym wypadku element główny transakcja zdefiniowano jako elementy typu typTransakcja, może on zawierać inne elementy, także elementy typów addres i typKsiążka. Typ adres zawiera elementy z nazwiskiem i adresem osoby, typ books zawiera elementy książka opisujące książki: jej tytuł, datę wydania i tak dalej. Za pomocą schematów można w pełni opisać składnię dokumentu książka.xml. W ramach nauki rozłożymy nasz schemat na kawałki.
Deklarowanie typów i elementów
Najważniejsze, co trzeba zrozumieć w przypadku schematów XML, to idea użycia typów prostych i złożonych oraz sposób powiązania ich z deklarowanymi elementami. W przeciwieństwie od DTD określa się typ deklarowanych elementów.
Zatem pierwszym krokiem przed rozpoczęciem deklarowania elementów jest sprawdzenie, czy dysponujemy potrzebnym typem, co zresztą często oznacza konieczność zdefiniowania nowego typu złożonego. Typy złożone mogą zawierać elementy i mieć atrybuty, typy proste nie mogą mieć ani elementów, ani atrybutów. Typy proste wbudowane w schematy XML przedstawiono w tabeli 3.2. Kiedy używasz tych typów w schemacie, pamiętaj o poprzedzeniu ich przedrostkiem schematów W3C, zwykle xsd:.
Tabela 3.2.
Typy proste wbudowane w specyfikację XML Schema
Typ |
Opis |
binary |
Wartości binarne, na przykład 110001. |
boolean |
Wartości takie, jak True i False czy 1 i 0. |
byte |
Wartość bajtowa, na przykład 123, nie większa niż 255. |
century |
Wiek, na przykład 20. |
date |
Data w postaci RRRR-MM-DD, na przykład 2001-10-15. |
decimal |
Liczby zapisane dziesiętnie, jak 5.4, 0 czy -219.06. |
double |
64-bitowa liczba zmiennoprzecinkowa podwójnej precyzji. |
ENTITIES |
Atrybut typu ENTITIES znany z XML 1.0. |
ENTITY |
Atrybut typu ENTITY znany z XML 1.0. |
float |
32-bitowa liczba zmiennoprzecinkowa pojedynczej precyzji. |
ID |
Atrybut typu ID znany z XML 1.0. |
IDREF |
Atrybut typu IDREF znany z XML 1.0. |
IDREFS |
Atrybut typu IDREFS znany z XML 1.0. |
int |
Liczba całkowita, na przykład 123456789. |
integer |
Liczba całkowita. |
language |
Identyfikator języka, taki jak de, fr czy en-US, zgodnie z odpowiednią definicją w XML 1.0. |
long |
Długa liczba całkowita, na przykład 1234567891234. |
month |
Określenie miesiąca, na przykład 2001-10. |
Name |
Typ danych Name znany z XML 1.0. |
NCName |
Nazwa XML bez przedrostka przestrzeni nazw i bez dwukropka. |
negativeInteger |
Ujemna liczba całkowita. |
NMTOKEN |
Atrybut typu NMTOKEN znany z XML 1.0. |
NMTOKENS |
Atrybut typu NMTOKENS znany z XML 1.0. |
nonNegativeInteger |
Liczba całkowita nieujemna. |
nonPositiveInteger |
Liczba całkowita niedodatnia. |
NOTATION |
Atrybut typu NOTATION znany z XML 1.0. |
positiveInteger |
Całkowita liczba dodatnia. |
QName |
Znany z XML 1.0 typ Namespace Qualified Name (nazwa z przestrzenią nazw). |
recurringDate |
Powtarzająca się data jak --10-15 oznaczająca każdy 15. października. |
recurringDay |
Powtarzający się dzień, na przykład ---31 oznaczający 15. każdego miesiąca. |
recurringDuration |
Powtarzający się czas, na przykład --10-15T12:00:00 oznaczający południe każdego 15. października według czasu uniwersalnego. |
short |
Krótka liczba całkowita, na przykład 12345. |
string |
Łańcuch tekstowy. |
time |
Czas, na przykład 12:00:00.000. |
timeDuration |
Czas trwania, na przykład P1Y2M3DT4H5M6.7S, czyli 1 rok, 2 miesiące, 3 dni, 4 godziny, pięć minut i 6,7 sekund. |
timeInstant |
Czas w postaci 2001-10-15T12:00:00.000-05:00 (czyli wraz ze strefą czasu). |
timePeriod |
--> Okres, na przykład 2001-10-15T12:00[Author:T] . |
unsignedByte |
Wartość bajtowa bez znaku. |
unsignedInt |
Liczba całkowita bez znaku. |
unsignedLong |
Długa liczba całkowita bez znaku. |
unsignedShort |
Krótka liczba całkowita bez znaku. |
uriReference |
Adres URI, na przykład http://www.w3c.org. |
year |
Rok, na przykład 2001. |
Jeśli istotne jest utrzymanie zgodności schematów XML z DTD, atrybuty należy deklarować tylko typów ID, IDREF, IDREFS, ENTITY, ENTITIES, NOTATION, NMTOKEN i NMTOKENS.
Nowe typy złożone definiuje się przy pomocy elementu xsd:complexType. Definicja typu złożonego zwykle sama zawiera deklaracje elementów, odwołania do innych elementów oraz deklaracje atrybutów. Elementy deklaruje się w elemencie xsd:element, a atrybuty w elemencie xsd:attribute. Tak jak w przypadku DTD, deklaracje elementów określają składnię elementu, jednak w schematach określony jest także typ elementu. Oprócz tego można podać typy atrybutów.
Oto fragment schematu książka.xsd, gdzie deklarujemy typ złożony adres zawierający adres opisywanej osoby:
<xsd:complexType name="adres">
<xsd:element name="nazwisko" type="xsd:string"/>
<xsd:element name="ulica" type="xsd:string"/>
<xsd:element name="miasto" type="xsd:string"/>
<xsd:element name="stan" type="xsd:string"/>
<xsd:attribute name="telefon" type="xsd:string"
use="optional"/>
</xsd:complexType>
Typ ten zostanie użyty do elementów właściciel i wypożyczający - oto odpowiednie deklaracje:
<xsd:complexType name="typTransakcja">
<xsd:element name="właściciel" type="adres"/>
<xsd:element name="wypożyczający" type="adres"/>
<xsd:element ref="uwagi" minOccurs="0"/>
<xsd:element name="książki" type= "typKsiążka"/>
<xsd:attribute name="dataWypożyczenia" type="xsd:date"/>
</xsd:complexType>
W definicji typu adres powiedziano, że elementy tego typu muszą mieć pięć innych elementów i jeden atrybutu. Elementami są nazwisko, ulica, miasto i stan, atrybut to telefon. Z kolei w deklaracjach tych elementów wewnętrznych nazwisko, ulica i miasto mają mieć typ xsd:string, natomiast stan jest typu NMTOKEN. Atrybut telefon jest napisem, xsd:string.
Deklaracja typu złożonego adres zawiera jedynie deklaracje oparte na typie prostym xsd:string. Nic jednak nie stoi na przeszkodzie, aby typy złożone zawierały w sobie elementy innych typów złożonych. Widać to w przypadku typu typTransakcja dotyczącego elementu głównego pliku książka.xml, transakcja. W tym wypadku dwa elementy, właściciel i wypożyczający, są typu złożonego Adres:
<xsd:complexType name="typTransakcja">
<xsd:element name="właściciel" type="adres"/>
<xsd:element name="wypożyczający" type="adres"/>
<xsd:element ref="uwagi" minOccurs="0"/>
<xsd:element name="książki" type="typKsiążka"/>
<xsd:attribute name="dataWypożyczenia" type="xsd:date"/>
</xsd:complexType>
Typ typTransakcja zawiera jeszcze atrybut dataWypożyczenia typu prostego xsd:date. Atrybuty zawsze są typu prostego, gdyż nie mogą mieć żadnej wewnętrznej struktury.
Po zdefiniowaniu nowego typu można użyć go do deklarowania elementów. Na przykład po zdefiniowaniu typu typTransakcja można zadeklarować element transakcja z tego typu korzystający:
<xsd:element name="transakcja" type="typTransakcja"/>
<xsd:complexType name="typTransakcja">
<xsd:element name="właściciel" type="adres"/>
<xsd:element name="wypożyczający" type="adres"/>
<xsd:element ref="uwagi" minOccurs="0"/>
<xsd:element name="książki" type="typKsiążka"/>
<xsd:attribute name="dataWypożyczenia" type="xsd:date"/>
</xsd:complexType>
Na razie widziałeś, jak użyć elementów xsd:element i xsd:attribute do deklarowania odpowiednio elementów i atrybutów oraz jak określić ich typy. Zobaczyłeś definiowanie typów złożonych za pomocą elementu xsd:complexType (typy proste nauczymy się tworzyć wkrótce).
Teraz przyjrzyjmy się deklaracji elementu uwagi:
<xsd:complexType name="typTransakcja">
<xsd:element name="właściciel" type="adres"/>
<xsd:element name="wypożyczający" type="adres"/>
<xsd:element ref="uwagi" minOccurs="0"/>
<xsd:element name="książki" type="typKsiążka"/>
<xsd:attribute name="dataWypożyczenia" type="xsd:date"/>
</xsd:complexType>
Tym razem nie deklarujemy nowego elementu, ale odwołujemy się do elementu już istniejącego. Faktycznie, element ten jest zdefiniowany gdzie indziej:
--> <xsd:element name="uwagi" type="xsd:string"/>[Author:T]
Użycie atrybutu ref pozwala włączyć do typu złożonego element zdefiniowany gdzie indziej. Jednak nie można tak odwołać się do dowolnego elementu - musi on zostać zadeklarowany globalnie, czyli nie może być zdefiniowany jako część żadnego typu złożonego. Deklaracja elementu lub atrybutu globalnego występuje bezpośrednio jako dziecko - a nie dalszy potomek - elementu xsd:schema. Element lub atrybut deklarowany globalnie może być też dowolnego typu złożonego. Użycie atrybutu ref jest bardzo silnym narzędziem, gdyż pozwala uniknąć wielokrotnego definiowania elementów, które występują w wielu miejscach w dokumencie.
Teraz przyjrzymy się, jak można określić krotność wystąpienia elementów w typie złożonym.
Określanie krotności wystąpień elementu
Element uwagi może wystąpić, bądź nie, w typie typTransakcja, gdyż przypisano mu atrybut minOccurs wskazujący, że minimalna liczba wystąpień to 0:
<xsd:complexType name="typTransakcja">
<xsd:element name="właściciel" type="adres"/>
<xsd:element name="wypożyczający" type="adres"/>
<xsd:element ref="uwagi" minOccurs="0"/>
<xsd:element name="książki" type="typKsiążka"/>
<xsd:attribute name="dataWypożyczenia" type="xsd:date"/>
</xsd:complexType>
Ogólnie rzecz biorąc najmniejszą dopuszczalną liczbę wystąpień elementu określa się za pomocą atrybutu minOccurs, największą dopuszczalną liczbę za pomocą atrybutu maxOccurs. Gdybyśmy chcieli umożliwić pojawianie się od zera do pięciu elementów uwagi w elementach typu typTransakcja, napisalibyśmy:
<xsd:complexType name="typTransakcja">
<xsd:element name="właściciel" type="adres"/>
<xsd:element name="wypożyczający" type="adres"/>
<xsd:element ref="uwagi" minOccurs="0" maxOccurs="5"/>
<xsd:element name="książki" type="typKsiążka"/>
<xsd:attribute name="dataWypożyczenia" type="xsd:date"/>
</xsd:complexType>
Wartością domyślną minOccurs jest 1, wartością domyślną maxOccurs jest wartość równa minOccurs. Jeśli chcesz zaznaczyć, że dany element może wystąpić dowolnie dużo razy, atrybutowi maxOccurs nadaj wartość unbounded.
Określanie wartości domyślnych elementów
W elementach xsd:element oprócz atrybutów minOccurs i maxOccurs możesz używać atrybutów fixed i default, przy czym zawsze używa się tylko jednego z nich. Pierwszy pozwala wskazać wartość obowiązującą, drugi wartość domyślną. Na przykład ustawienie fixed na 400 oznacza, że wartością elementu zawsze musi być 400. Ustawienie na tę wartość atrybutu default oznacza, że wartością domyślną elementu będzie 400, ale jeśli element w dokumencie wystąpi, przyjęta zostanie faktycznie użyta w nim wartość.
W poniższym przykładzie żądamy, aby element liczbaPrób miał wartość 100:
<xsd:element name="liczbaPrób" type="xsd:integer" fixed="100"/>
Teraz z kolei nadamy temu samemu elementowi wartość domyślną 100, dzięki czemu jeśli użytkownik poda w dokumencie inną wartość, to zostanie ona zaakceptowana. Jeśli użytkownik nie poda żadnej wartości, przyjęte zostanie 100:
<xsd:element name="liczbaPrób" type="xsd:integer" default="100"/>
Ograniczenia atrybutów i wartości domyślne
Tak samo jak w przypadku elementów, tak i atrybutom przypisuje się typy, jednak atrybuty muszą mieć zawsze typ prosty. Atrybutom nie można nadawać atrybutów minOccurs i maxOccurs, jako że zgodnie ze specyfikacją XML każdy atrybut może wystąpić co najwyżej raz. Z kolei wartości atrybutów można ograniczać na inne sposoby.
Atrybuty deklaruje się w elemencie xsd:attribute. Sam ten element ma atrybut type określający typ (prosty) definiowanego atrybutu. To, czy atrybut jest obowiązkowy, czy opcjonalny oraz ewentualną wartość domyślną i wartość stałą atrybutu określa się przy pomocy atrybutów use i value. Atrybut use może mieć wartość required lub optional, co odpowiada odpowiednio atrybutom obowiązkowym i opcjonalnym. W pierwszym wypadku value oznacza wartość stałą atrybutu, w drugim wartość domyślną.
W poniższym przykładzie do typu adres dodano opcjonalny atrybut telefon typu xsd:string:
<xsd:complexType name="adres">
<xsd:element name="nazwisko" type="xsd:string"/>
<xsd:element name="ulica" type="xsd:string"/>
<xsd:element name="miasto" type="xsd:string"/>
<xsd:element name="stan" type="xsd:string"/>
<xsd:attribute name="telefon" type="xsd:string"
use="optional"/>
</xsd:complexType>
Oto wszystkie dopuszczalne wartości atrybutu use:
required - atrybut jest obowiązkowy, może mieć dowolną wartość.
optional - atrybut jest opcjonalny, może mieć dowolną wartość.
fixed - atrybut ma wartość ustaloną podaną w atrybucie value.
default - jeśli atrybut nie zostanie podany jawnie, przypisana mu zostanie wartość podana w value. Jeśli atrybut zostanie podany jawnie, może mieć dowolną wartość.
prohibited - użycie atrybutu jest zabronione.
Rozważmy na przykład następującą deklarację atrybutu:
<xsd:attribute name="licznik" type="xsd:int"
use="fixed" value="400">
W deklaracji tej tworzymy atrybut całkowitoliczbowy licznik, którego wartością jest zawsze 400. A oto deklaracja następna:
<xsd:attribute name="licznik" type="xsd:int"
use="default" value="400">
Tym razem atrybut licznik ma wartość domyślną 400, która będzie zastosowana tylko wtedy, gdy atrybut ten nie zostanie podany jawnie.
Tworzenie typów prostych
Większość typów używanych w tej książce to typy proste wbudowane w specyfikację schematów XML, takie jak xsd:string, xsd:integer, xsd:date i tak dalej. Przyjrzyj się jednak atrybutowi IDksiążki - zdefiniowano go jako atrybut typu IDKatalogu:
<xsd:complexType name="typKsiążka">
<xsd:element name="książka" minOccurs="0" maxOccurs="10">
<xsd:complexType>
<xsd:element name="tytuł" type="xsd:string"/>
<xsd:element name="dataWydania" type="xsd:date" minOccurs='0'/>
<xsd:element name="wartość" type="xsd:decimal"/>
<xsd:element name="terminMaksymalny">
<xsd:simpleType base="xsd:integer">
<xsd:maxExclusive value="14"/>
</xsd:simpleType>
</xsd:element>
<xsd:attribute name="IDksiążki" type="IDKatalogu"/>
</xsd:complexType>
</xsd:element>
</xsd:complexType>
Typ IDKatalogu jest typem prostym, który zdefiniowaliśmy sami następująco:
<xsd:simpleType name="IDKatalogu" base="xsd:string">
<xsd:pattern value="\d{3}-\d{4}-\d{3}"/>
</xsd:simpleType>
Zwróć uwagę, że definicja nowego typu prostego zawsze oparta jest na innym, już istniejącym typie prostym (wbudowanym lub zdefiniowanym przez użytkownika; w tym wypadku użyliśmy jako typu bazowego xsd:string). Do wskazania typu bazowego używa się atrybutu base elementu xsd:simpleType - w naszym wypadku ustawienie to wyglądało tak: base="xsd:string". Do opisania właściwości nowych typów prostych w schematach XML używa się fazowania --> owanie[Author:w] (ang. facet), które omawiamy dalej.
Tworzenie typów prostych przy pomocy fazowaniaowania
Użycie fazowania umożliwia ograniczenie zakresu wartości, jakie może przybierać typ prosty. Załóżmy na przykład, że potrzebny jest nam typ prosty dzieńMiesiąca, który pozwala przechowywać liczby całkowite od 1 do 31. Jako typ bazowy wybierzemy xsd:integer, skorzystamy z dwóch fazowaniaowań: minInclusive i maxInclusive:
<xsd:simpleType name=dzieńMiesiąca" base="xsd:integer">
<xsd:minInclusive value="1"/>
<xsd:maxInclusive value="31"/>
</xsd:simpleType>
Po stworzeniu nowego typu prostego możemy definiować należące do niego elementy i atrybuty.
Typ prosty IDKatalogu utworzony w pliku książka.xsd jest znacznie bogatszy niż typ dzieńMiesiąca, gdyż za pomocą fazowania pattern określiliśmy wyrażenie regularne, do którego muszą pasować jego wartości (wyrażenie regularne to zapisany jako tekst wymagany format danych):
<xsd:simpleType name="IDKatalogu" base="xsd:string">
<xsd:pattern value="\d{3}-\d{4}-\d{3}"/>
</xsd:simpleType>
Tekst podawany jako wartość typu IDKatalogu musi pasować do wyrażenia regularnego \d{3}-\d{4}-\d{3}, które oznacza trzy cyfry, minus, cztery cyfry, minus i znowu trzy cyfry.
Wyrażenia regularne
Wyrażenia regularne używane w fazowaniu schematów XML są tymi samymi wyrażeniami regularnymi, co wyrażenia używane w języku programowania Perl. Pełną dokumentację perlowych wyrażeń znajdziesz w witrynie CPAN pod adresem www.cpan.org/doc/manual/html/pod/perlre.html (choć warto zaznaczyć, że wyrażenia regularne wykraczają poza zakres tej książki).
Typ IDKatalogu używany jest w atrybucie IDksiążki elementu książka, zatem wartości tego atrybutu z dokumentu książka.xml muszą z pokazanym wyrażeniem regularnym zgodne:
<książka IDksiążki="123-4567-890">
<tytuł>Trzęsienia ziemi na dzień dobry</tytuł>
<dataWydania>2001-10-20</dataWydania>
<wartość>15.95</wartość>
<terminMaksymalny>14</terminMaksymalny>
</książka>
Jakie są fazowania i których typów prostych dotyczą? Istnieje siedem fazowania ogólnych, które wraz z informacją o ich dostępności w poszczególnych typach prostych zestawiono w tabeli 3.3.
Tabela 3.3.
Typy proste wraz z odpowiadającymi im fazowaniem
Typ |
Length |
minLength |
maxLength |
Pattern |
Enumeration |
binary |
x |
X |
x |
x |
x |
boolean |
|
|
|
x |
|
byte |
|
|
|
x |
x |
century |
|
|
|
x |
x |
date |
|
|
|
x |
x |
decimal |
|
|
|
x |
x |
double |
|
|
|
x |
x |
ENTITIES |
x |
x |
x |
|
x |
ENTITY |
x |
x |
x |
x |
x |
float |
|
|
|
x |
x |
ID |
x |
x |
x |
x |
x |
IDREF |
x |
x |
x |
x |
x |
IDREFS |
x |
x |
x |
|
x |
int |
|
|
|
x |
x |
integer |
|
|
|
x |
x |
language |
x |
x |
x |
x |
x |
long |
|
|
|
x |
x |
month |
|
|
|
x |
x |
Name |
x |
x |
x |
x |
x |
NCName |
x |
x |
x |
x |
x |
negativeInteger |
|
|
|
x |
x |
NMTOKEN |
x |
x |
x |
x |
x |
NMTOKENS |
x |
x |
x |
|
x |
nonNegativeInteger |
|
|
|
x |
x |
nonPositiveInteger |
|
|
|
x |
x |
NOTATION |
x |
x |
x |
x |
x |
positiveInteger |
|
|
|
x |
x |
QName |
x |
x |
x |
x |
x |
recurringDate |
|
|
x |
x |
|
recurringDay |
|
|
x |
x |
|
recurringDuration |
|
|
x |
x |
|
short |
|
|
|
x |
x |
string |
x |
x |
x |
x |
x |
time |
|
|
|
x |
x |
timeDuration |
|
|
x |
x |
|
timeInstant |
|
|
x |
x |
|
timePeriod |
|
|
x |
x |
|
unsignedByte |
|
|
|
x |
x |
unsignedInt |
|
|
|
x |
x |
unsignedLong |
|
|
|
x |
x |
unsignedShort |
|
|
|
x |
x |
uriReference |
x |
x |
x |
x |
x |
year |
|
|
|
x |
x |
Typy numeryczne oraz inne typy proste, dla których można określić kolejność, mogą mieć też pewne dodatkowe fazowania - zestawiono je w tabelach 3.4 i 3.5.
Tabela 3.4.
Fazowania związane z dającymi się uporządkować typami prostymi, część pierwsza
Typ |
MaxInclusive |
maxExclusive |
minInclusive |
Binary |
X |
x |
x |
Byte |
X |
x |
x |
Century |
X |
x |
x |
Date |
x |
x |
x |
Decimal |
x |
x |
x |
Double |
x |
x |
x |
Float |
x |
x |
x |
Int |
x |
x |
x |
Integer |
x |
x |
x |
language |
x |
x |
x |
Long |
x |
x |
x |
Month |
x |
x |
x |
negativeInteger |
x |
x |
x |
nonNegativeInteger |
x |
x |
x |
nonPositiveInteger |
x |
x |
x |
positiveInteger |
x |
x |
x |
recurringDate |
x |
x |
x |
recurringDay |
x |
x |
x |
recurringDuration |
x |
x |
x |
Short |
x |
x |
x |
String |
x |
x |
x |
Time |
x |
x |
x |
timeDuration |
x |
x |
x |
timeInstant |
x |
x |
x |
timePeriod |
x |
x |
x |
unsignedByte |
x |
x |
x |
unsignedInt |
x |
x |
x |
unsignedLong |
x |
x |
x |
unsignedShort |
x |
x |
x |
uriReference |
x |
x |
x |
Year |
x |
x |
x |
Tabela 3.5.
Fazowania związane z dającymi się uporządkować typami prostymi, część druga
Typ |
minExclusive |
Precision |
Scale |
Encoding |
Binary |
|
|
|
x |
Byte |
x |
x |
x |
|
Century |
x |
|
|
|
Date |
x |
|
|
|
Decimal |
x |
x |
x |
|
Double |
x |
|
|
|
Float |
x |
|
|
|
Int |
x |
x |
x |
|
Integer |
x |
x |
x |
|
language |
x |
x |
x |
|
Long |
x |
x |
x |
|
Month |
x |
|
|
|
negativeInteger |
x |
x |
x |
|
nonNegativeInteger |
x |
x |
x |
|
nonPositiveInteger |
x |
x |
x |
|
positiveInteger |
x |
x |
x |
|
recurringDate |
x |
|
|
|
recurringDay |
x |
|
|
|
recurringDuration |
x |
|
|
|
Short |
x |
x |
x |
|
String |
x |
|
|
|
Time |
x |
|
|
|
timeDuration |
x |
|
|
|
timeInstant |
x |
|
|
|
timePeriod |
x |
|
|
|
unsignedByte |
x |
x |
x |
|
unsignedInt |
x |
x |
x |
|
unsignedLong |
x |
x |
x |
|
unsignedShort |
x |
x |
x |
|
uriReference |
x |
x |
x |
|
Year |
x |
|
|
|
Istnieje jeszcze grupa fazowania związanych z typami daty, zestawiono je w tabeli 3.6.
Tabela 3.6.
Typ |
Period |
Duration |
Century |
x |
x |
Date |
x |
x |
Month |
x |
x |
recurringDate |
x |
x |
recurringDay |
x |
x |
recurringDuration |
x |
x |
Time |
x |
x |
timeDuration |
x |
x |
timeInstant |
x |
x |
timePeriod |
x |
x |
Year |
x |
x |
Spośród wszystkich operacji fazowania zestawionych w tabelach 3.3, 3.4 i 3.5 moimi ulubionymi są minInclusive, maxInclusive, pattern oraz enumeration. Pierwsze trzy już poznaliśmy, czwartej jeszcze nie.
Fazowanie enumeration umożliwia wyliczenie dopuszczalnych wartości (to samo można zrobić w DTD). Użycie tego fazowania powoduje, że użytkownik nie może wybierać dowolnych wartości, ale tylko wartości spośród podanych.
Załóżmy na przykład, że potrzebny jest nam typ prosty dzieńTygodnia, którego wartościami mogą być jedynie nazwy dni tygodnia. Definicja tego typu będzie wyglądała tak:
<xsd:simpleType name="dzieńTygodnia" base="xsd:string">
<xsd:enumeration value="Niedziela"/>
<xsd:enumeration value="Poniedziałek"/>
<xsd:enumeration value="Wtorek"/>
<xsd:enumeration value="Środa"/>
<xsd:enumeration value="Czwartek"/>
<xsd:enumeration value="Piątek"/>
<xsd:enumeration value="Sobota"/>
</xsd:simpleType>
Użycie anonimowych definicji typów
Jak dotąd we wszystkich deklaracjach elementów w naszym schemacie książka.xsd używaliśmy atrybutu type do określenia typu nowego elementu. Czy nie ma jednak prostszej drogi w przypadku, gdy chcemy jakiegoś typu użyć tylko w jednym miejscu? Po co wymyślać nazwy typów, jeśli nie będą potrzebne więcej niż raz?
Okazuje się, że jest prostszy sposób - jeśli jakiegoś typu użyć należy tylko raz, tworzy się anonimową definicję typu. Oznacza to po prostu wstawienie elementu xsd:simpleType lub xsd:complexType do deklaracji elementu, xsd:element. W takim wypadku nie trzeba przypisywać atrybutowi type żadnej wartości, tak utworzony typ nie ma nazwy.
Oto przykład z pliku książka.xsd, kiedy definicji typu anonimowego używamy do elementu książka. Każdy element zawierać ma elementy tytuł, dataWydania, wartość i terminMaksymalny, poza tym potrzebny nam będzie atrybut IDksiążki - zatem mamy doskonałego kandydata na typ złożony. Zamiast jednak deklarować specjalny typ, element xsd:complexType wstawimy do elementu xsd:element służącego do zadeklarowania elementu książka:
<xsd:element name="książka" minOccurs="0" maxOccurs="10">
<xsd:complexType>
.
.
.
</xsd:complexType>
</xsd:element>
Teraz możemy spokojnie dodawać definicje tego, co ma się w elemencie książka znaleźć:
<xsd:element name="książka" minOccurs="0" maxOccurs="10">
<xsd:complexType>
<xsd:element name="tytuł" type="xsd:string"/>
<xsd:element name="dataWydania" type="xsd:date" minOccurs='0'/>
<xsd:element name="wartość" type="xsd:decimal"/>
.
.
.
--> </xsd:complexType>[Author:T]
</xsd:element>
Można też używać anonimowych typów prostych, na przykład element terminMaksymalny zawiera największą liczbę dni, na którą można wypożyczyć książkę. Liczba ta nie może przekroczyć wartości 14, co zapisujemy stosując definicję anonimowego typu prostego stosując fazowanie maxExclusive:
<xsd:element name="książka" minOccurs="0" maxOccurs="10">
<xsd:complexType>
<xsd:element name="tytuł" type="xsd:string"/>
<xsd:element name="dataWydania" type="xsd:date" minOccurs='0'/>
<xsd:element name="wartość" type="xsd:decimal"/>
<xsd:element name="terminMaksymalny">
<xsd:simpleType base="xsd:integer">
<xsd:maxExclusive value="14"/>
</xsd:simpleType>
</xsd:element>
<xsd:attribute name="IDksiążki" type="IDKatalogu"/>
</xsd:complexType>
</xsd:element>
W anonimowej definicji typu można także deklarować atrybuty:
<xsd:element name="książka" minOccurs="0" maxOccurs="10">
<xsd:complexType>
<xsd:element name="tytuł" type="xsd:string"/>
<xsd:element name="dataWydania" type="xsd:date" minOccurs='0'/>
<xsd:element name="wartość" type="xsd:decimal"/>
<xsd:element name="terminMaksymalny">
<xsd:simpleType base="xsd:integer">
<xsd:maxExclusive value="14"/>
</xsd:simpleType>
</xsd:element>
<xsd:attribute name="IDksiążki" type="IDKatalogu"/>
</xsd:complexType>
</xsd:element>
Teraz przyjrzymy się definiowaniu elementów pustych.
Tworzenie elementów pustych
Elementy puste nie mają zawartości, ale mogą mieć atrybuty. Deklaruje się je stosując ich typ jako xsd:complexType i ustawiając atrybut content na wartość empty. Oto przykład - tworzymy pusty element obrazek mogący mieć trzy atrybuty: źródło, szerokość i wysokość, na przykład <obrazek źródło="/images/cover.gif" height="256" width="512"/>. Zaczynamy od zadeklarowania samego elementu:
<xsd:element name="obrazek">
.
.
.
</xsd:element>
W deklaracji tego elementu nie użyliśmy atrybutu type, gdyż zastosujemy anonimową definicję typu. Aby stworzyć typ anonimowy, użyjemy elementu complexType; wartością atrybutu content jest empty:
<xsd:element name="obrazek">
<xsd:complexType content="empty">
.
.
.
</complexType>
</xsd:element>
W końcu dodajemy definicje atrybutów definiowanego elementu:
<xsd:element name="obrazek">
<xsd:complexType content="empty">
<xsd:attribute name="źródło" type="xsd:string"/>
<xsd:attribute name="szerokość" type="xsd:decimal"/>
<xsd:attribute name="wysokość" type="xsd:decimal"/>
</complexType>
</xsd:element>
I to już wszystko - element pusty obrazek jest gotów do użycia.
Tworzenie elementów o zawartości mieszanej
Jak dotąd wszelkie treści tekstowe w dokumentach z tego rozdziału były pogrzebane na najniższym poziomie elementów, czyli w elementach nie posiadających już elementów potomnych. Jak jednak wiesz, można też tworzyć elementy o zawartości mieszanej, czyli zawierające tak inne elementy, jak i tekst. W takich elementach treści tekstowe pojawiają się na tym samym poziomie, co elementy potomne.
Oto przykładowy dokument zawierający elementy z treścią mieszaną. Do naszego schematu książka.xsd dodajemy element przypominajka zawierający list do osoby, która pożyczyła książkę:
<?xml version="1.0" encoding="iso-8859-2"?>
<przypominajka>
Szanowna Pani <nazwisko>Britta Regensburg</nazwisko>:
Książka <tytuł>Skakanie po wulkanach</tytuł> wypożyczona
została jedynie na <terminMaksymalny>14</terminMaksymalny>
dni. Proszę ją zwrócić lub wpłacić <wartość>17.99</wartość>.
Dziękuję.
</przypominajka>
W tym dokumencie w elemencie przypominajka używamy zarówno wcześniej zdefiniowanych elementów, jak i danych znakowych. Nasz nowy element ma treść mieszaną, definiowanie go w schemacie zaczniemy od utworzenia anonimowego typu złożonego:
<xsd:element name="przypominajka">
<xsd:complexType>
.
.
.
</xsd:complexType>
</xsd:element>
Przypomnij sobie, że element xsd:complexType ma atrybut content określający model zawartości - tym razem nadamy mu wartość mixed:
<xsd:element name="przypominajka">
<xsd:complexType content="mixed">
.
.
.
</xsd:complexType>
</xsd:element>
Teraz wystarczy już tylko dodać elementy, które mogą się znaleźć wewnątrz elementu przypominajka:
<xsd:element name="przypominajka">
<xsd:complexType content="mixed">
<xsd:element name="nazwisko" type="xsd:string"/>
<xsd:element name="tytuł" type="xsd:string"/>
<xsd:element name="terminMaksymalny">
<xsd:simpleType base="xsd:integer">
<xsd:maxExclusive value="14"/>
</xsd:simpleType>
</xsd:element>
<xsd:element name="wartość" type="xsd:decimal"/>
</xsd:complexType>
</xsd:element>
O ile w przypadku użycia DTD nie można było określić w zawartości mieszanej kolejności występowania poszczególnych elementów, to w schematach XML można określić zarówno kolejność, jak i krotność poszczególnych elementów potomnych.
W ogóle trzeba stwierdzić, że wymagania względem procesora XML, który ma obsługiwać schematy XML, są duże - procesor taki musi przecież między innymi obsługiwać pełną składnię perlowych wyrażeń regularnych, aby móc zinterpretować fazowanie pattern. W wyniku tego spodziewać się można, że jeszcze dużo czasu upłynie zanim pojawi się procesor w pełni obsługujący schematy.
Elementy typu elementOnly i textOnly
Wiesz już, że używając atrybutu content elementu xsd:complexType można wskazać model zawartości - na przykład pusty czy mieszany - ale pojawia się pytanie, jaki był model zawartości, kiedy używaliśmy elementu xsd:complexType w ogóle nie podając wartości tego atrybutu? Oto na przykład deklaracja typu typTransakcja:
<xsd:element name="transakcja" type="typTransakcja"/>
<xsd:complexType name="typTransakcja">
<xsd:element name="właściciel" type="adres"/>
<xsd:element name="wypożyczający" type="adres"/>
<xsd:element ref="uwagi" minOccurs="0"/>
<xsd:element name="książki" type=„typKsiążka”/>
<xsd:attribute name="dataWypożyczenia" type="xsd:date"/>
</xsd:complexType>
Modelem domyślnym dla typów złożonych jest elementOnly, co oznacza, że w zawartości pojawiać się mogą tylko inne elementy. Oznacza to, że powyższa deklaracja jest równoważna deklaracja, w której atrybut content podano jawnie:
<xsd:element name="transakcja" type="typTransakcja"/>
<xsd:complexType name="typTransakcja" content="elementOnly">
<xsd:element name="właściciel" type="adres"/>
<xsd:element name="wypożyczający" type="adres"/>
<xsd:element ref="uwagi" minOccurs="0"/>
<xsd:element name="książki" type=„typKsiążka”/>
<xsd:attribute name="dataWypożyczenia" type="xsd:date"/>
</xsd:complexType>
Jeśli jednak typ złożony jest wyprowadzany z typu prostego, domyślnym modelem zawartości jest już textOnly - co oznacza, że definiowane elementy będą mogły mieć treść tylko tekstową, czyli procesor XML nie będzie w żaden sposób tej zawartości kontrolował składniowo.
Model zawartości textOnly można też zdefiniować jawnie, jak w poniższym przykładzie, gdzie tworzymy nową wersję elementu IDksiążki, aby umożliwić zastosowanie także innych postaci indeksu książki:
<xsd:element name="IDksiążki">
<xsd:complexType content="textOnly">
<xsd:attribute name="typIndeksu" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
Wynik jest taki, że otrzymamy element IDksiążki, który zawierać może dowolny tekst (ale nie może zawierać żadnych elementów), a procesor XML nie będzie sprawdzał składni tej zawartości.
W3C nie zaleca całkowitego rezygnowania z kontroli nad składnią, zresztą nietrudno jest utworzyć wyrażenia opisujące alternatywne wzorce. W naszym przypadku można byłoby użyć typu prostego opartego na typie xsd:string i ograniczyć dopuszczalne wartości stosując fazowanie pattern.
Komentarze w schematach
W DTD można umieszczać komentarze objaśniające wybrane fragmenty definicji. Schematy są bardziej złożone, więc i komentarze mogą być bardziej zróżnicowane - używa się trzech różnych elementów: xsd:annotation, xsd:documentation i xsd:appInfo.
Element xsd:annotation to swoisty pojemnik na pozostałe dwa elementy. xsd:documentation zawiera tekst będący typowym komentarzem, czyli przeznaczony dla ludzi czytających dokument. Z kolei xsd:appInfo zawiera treści przeznaczone dla aplikacji dokument odczytujących.
Oto przykład użycia elementów xsd:annotation i xsd:appInfo. Jest to przykład pochodzący ze schematów W3C opisujących schematy XML, czyli jest to po prostu część schematu schematów. Jest to deklaracja typu prostego string, element appInfo wskazuje, jakie właściwości i fazowania dostępne są dla innych aplikacji (użyto tu elementu appInfo, a nie xsd:appInfo dlatego, że w tym schemacie przestrzeń schematów XML jest przestrzenią domyślną).
<simpleType name="string" base="urSimpleType">
<annotation>
<appinfo>
<has-facet name="length"/>
<has-facet name="minLength"/>
<has-facet name="maxLength"/>
<has-facet name="pattern"/>
<has-facet name="enumeration"/>
<has-facet name="maxInclusive"/>
<has-facet name="maxExclusive"/>
<has-facet name="minInclusive"/>
<has-facet name="minExclusive"/>
<has-property name="ordered" value="true"/>
<has-property name="bounded" value="false"/>
<has-property name="cardinality" value="countably infinite"/>
<has-property name="numeric" value="false"/>
</appinfo>
</annotation>
</simpleType>
Oto kolejny przykład, tym razem pochodzący już z pliku książka.xsd, w którym użyto elementów xsd:annotation i xsd:documentation i wstawiono w nich dodatkowe wyjaśnienie zaraz na początku schematu:
<xsd:schema xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<xsd:annotation>
<xsd:documentation>
Schemat opisujący pożyczenie książek.
</xsd:documentation>
</xsd:annotation>
<xsd:element name="transakcja" type="typTransakcja"/>
<xsd:complexType name="typTransakcja">
<xsd:element name="właściciel" type="adres"/>
<xsd:element name="wypożyczający" type="adres"/>
<xsd:element ref="uwagi" minOccurs="0"/>
<xsd:element name="książki" type=„typKsiążka”/>
<xsd:attribute name="dataWypożyczenia" type="xsd:date"/>
</xsd:complexType>
.
.
.
Tak naprawdę elementu xsd:annotation można użyć na początku większości konstrukcji schematów, na przykład przy elementach xsd:schema, xsd:complexType, xsd:simpleType, xsd:element, xsd:attribute i innych. Oto przykład, w którym dodano komentarz do definicji typu złożonego:
<xsd:schema xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<xsd:annotation>
<xsd:documentation>
Schemat opisujący pożyczenie książek.
</xsd:documentation>
</xsd:annotation>
<xsd:element name="transakcja" type="typTransakcja"/>
<xsd:complexType name="typTransakcja">
<xsd:annotation>
<xsd:documentation>
Typ ten używany jest w elemencie głównym.
</xsd:documentation>
</xsd:annotation>
<xsd:element name="właściciel" type="adres"/>
<xsd:element name="wypożyczający" type="adres"/>
<xsd:element ref="uwagi" minOccurs="0"/>
<xsd:element name="książki" type="typKsiążka"/>
<xsd:attribute name="dataWypożyczenia" type="xsd:date"/>
</xsd:complexType>
.
.
.
Tak samo jak w DTD można używać albo sekwencji, albo wyborów, to samo można robić w schematach XML.
Tworzenie wyborów
Wybór umożliwia wskazanie szeregu elementów, z których wybrany zostanie zawsze tylko jeden. W schematach XML do stworzenia wyboru używa się elementu xsd:choice. Oto przykład - nasz typ typTransakcja zmienimy tak, aby można było opisywać albo wypożyczenie wielu książek, albo tylko jednej. Stosujemy w tym celu element xsd:choice zawierający elementy książki oraz książka. Konieczne było przy tym udostępnienie globalnie definicji elementu książka, więc deklaracja została usunięta z wnętrza definicji elementu książki.
<xsd:complexType name="typTransakcja">
<xsd:element name="właściciel" type="adres"/>
<xsd:element name="wypożyczający" type="adres"/>
<xsd:element ref="uwagi" minOccurs="0"/>
<xsd:choice>
<xsd:element name="książki" type=„typKsiążka”/>
<xsd:element ref="książka"/>
</xsd:choice>
<xsd:attribute name="dataWypożyczenia" type="xsd:date"/>
</xsd:complexType>
<xsd:complexType name=„typKsiążka”>
<xsd:element ref="książka" minOccurs="0" maxOccurs="10"/>
</xsd:complexType>
<xsd:element name="książka">
<xsd:complexType>
<xsd:element name="tytuł" type="xsd:string"/>
<xsd:element name="dataWydania" type="xsd:date" minOccurs='0'/>
<xsd:element name="wartość" type="xsd:decimal"/>
<xsd:element name="terminMaksymalny">
<xsd:simpleType base="xsd:integer">
<xsd:maxExclusive value="14"/>
</xsd:simpleType>
</xsd:element>
<xsd:attribute name="IDksiążki" type="IDKatalogu"/>
</xsd:complexType>
</xsd:element>
Tworzenie sekwencji
Domyślnie w elementach danego typu muszą pojawić się wszystkie elementy wskazane w typie złożonym. Okazuje się jednak, że sekwencję można także tworzyć jawnie za pomocą elementu xsd:sequence.
Załóżmy na przykład, że można pożyczać nie tylko książki, ale także pisma. Wobec tego utworzymy nową grupę książkaICzasopismo. Grupa spina elementy w całość. Grupom można nadawać nazwy i można je potem włączać w inne elementy za pomocą elementu xsd:group podając odpowiednią nazwę grupy:
<xsd:complexType name="typTransakcja">
<xsd:element name="właściciel" type="adres"/>
<xsd:element name="wypożyczający" type="adres"/>
<xsd:element ref="uwagi" minOccurs="0"/>
<xsd:choice>
<xsd:element name="książki" type=„typKsiążka”/>
<xsd:element ref="książka"/>
<xsd:group ref="książkaICzasopismo"/>
</xsd:choice>
<xsd:attribute name="dataWypożyczenia" type="xsd:date"/>
</xsd:complexType>
Do utworzenia grupy książkaICzasopismo używa się elementu xsd:group; aby wymusić kolejność pojawiania się elementów w grupie, używa się elementu xsd:sequence:
<xsd:complexType name="typTransakcja">
<xsd:element name="właściciel" type="adres"/>
<xsd:element name="wypożyczający" type="adres"/>
<xsd:element ref="uwagi" minOccurs="0"/>
<xsd:choice>
<xsd:element name="książki" type=„typKsiążka”/>
<xsd:element ref="książka"/>
<xsd:group ref="książkaICzasopismo"/>
</xsd:choice>
<xsd:attribute name="dataWypożyczenia" type="xsd:date"/>
</xsd:complexType>
<xsd:complexType name=„typKsiążka”>
<xsd:element ref="książka" minOccurs="0" maxOccurs="10"/>
</xsd:complexType>
<xsd:group name="książkaICzasopismo">
<xsd:sequence>
<xsd:element ref="książki"/>
<xsd:element ref="pismo"/>
</xsd:sequence>
</xsd:group>
<xsd:element name="książka">
<xsd:complexType>
<xsd:element name="tytuł" type="xsd:string"/>
<xsd:element name="dataWydania" type="xsd:date" minOccurs='0'/>
<xsd:element name="wartość" type="xsd:decimal"/>
<xsd:element name="terminMaksymalny">
<xsd:simpleType base="xsd:integer">
<xsd:maxExclusive value="14"/>
</xsd:simpleType>
</xsd:element>
<xsd:attribute name="IDksiążki" type="IDKatalogu"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="pismo">
<xsd:complexType>
<xsd:element name="tytułPisma" type="xsd:string"/>
<xsd:element name="dataWydania" type="xsd:date" minOccurs='0'/>
<xsd:element name="terminMaksymalny">
<xsd:simpleType base="xsd:integer">
<xsd:maxExclusive value="14"/>
</xsd:simpleType>
</xsd:element>
<xsd:attribute name="IDpisma" type="IDKatalogu"/>
</xsd:complexType>
</xsd:element>
Tworzenie grup atrybutów
Za pomocą elementu xsd:attributeGroup można tworzyć grupy atrybutów. Jeśli chcemy na przykład do elementu książka dodać szereg atrybutów element ten opisujących, możemy utworzyć grupę atrybutów opisKsiążki i później w deklaracji tego elementu do takiej grupy się odwołać:
<xsd:element name="książka">
<xsd:complexType>
<xsd:element name="tytuł" type="xsd:string"/>
<xsd:element name="dataWydania" type="xsd:date" minOccurs='0'/>
<xsd:element name="wartość" type="xsd:decimal"/>
<xsd:element name="terminMaksymalny">
<xsd:simpleType base="xsd:integer">
<xsd:maxExclusive value="14"/>
</xsd:simpleType>
</xsd:element>
<xsd:attributeGroup ref="opisKsiążki"/>
</xsd:complexType>
</xsd:element>
Do tworzenia grupy atrybutów opisKsiążki używa się po prostu elementu xsd:attributeGroup zamykając w nim wszystkie potrzebne atrybuty przy pomocy elementów xsd:attribute:
Znaczna część tego kodu jest zbędna.
<xsd:attributeGroup name="opisKsiążki">
<xsd:attribute name="IDksiążki" type="IDKatalogu"/>
<xsd:attribute name="liczbaStron" type="xsd:decimal"/>
<xsd:attribute name="typOkładki">
<xsd:simpleType base="xsd:string">
<xsd:enumeration value="skóra"/>
<xsd:enumeration value="płótno"/>
<xsd:enumeration value="winyl"/>
</xsd:simpleType>
</xsd:attribute>
</xsd:attributeGroup>
Grupy a encje parametryczne
Tworzenie grup elementów lub atrybutów i potem odwoływanie się do takich grup w definicjach innych elementów bardzo podobne są do encji parametrycznych w DTD.
Tak więc schematy zawierają wyrafinowane mechanizmy pozwalające składać dokumenty z fragmentów.
Tworzenie grup all
W schematach XML istnieje jeszcze jeden rodzaj grup: grupy typu all. Wszystkie elementy z takiej grupy mogą pojawić się raz lub mogą się nie pojawiać, nie ma też znaczenia ich kolejność. Grup używać trzeba na najwyższym poziomie modelu zawartości, a wszystkie dzieci takiej grupy muszą być zwykłymi elementami, czyli taka grupa nie może już zawierać innych grup. Oprócz tego elementy w tym modelu zawartości nie mogą pojawić się więcej niż raz (czyli minOccurs i maxOccurs mogą mieć tylko wartości 0 i 1).
Oto przykład, w którym przekształciliśmy typ typTransakcja na grupę typu all:
<xsd:complexType name="typTransakcja">
<xsd:all>
<xsd:element name="właściciel" type="adres"/>
<xsd:element name="wypożyczający" type="adres"/>
<xsd:element ref="uwagi" minOccurs="0"/>
<xsd:element name="książki" type="typKsiążka"/>
</xsd:all>
<xsd:attribute name="dataWypożyczenia" type="xsd:date"/>
</xsd:complexType>
Elementy zdefiniowane w takim typie pojawiać się mogą w dowolnej kolejności, ale każdy z nich nie może pojawić się więcej niż raz. Oprócz tego grupa xsd:all zawierać musi wszystkie elementy należące do modelu zawartości - nie można już dodać żadnych elementów poza grupą.
Schematy i przestrzenie nazw
Jedną z ważnych zalet schematów XML jest możliwość walidowania przez procesory XML dokumentów zawierających przestrzenie nazw (w przypadku DTD jest to problemem). Po to właśnie element schema ma atrybut targetNamespace. W atrybucie tym określa się przestrzeń docelową, dla której schemat jest przeznaczony. Znaczy to, że jeśli procesor waliduje dokument i sprawdza elementy w określonej przestrzeni, będzie umiał na podstawie przestrzeni nazw odnaleźć schemat. Właśnie po to stworzono docelowe przestrzenie nazw: aby można było wskazać przestrzeń nazw, dla której schemat jest przeznaczony, dzięki czemu procesor XML może sam określić schemat, którego do walidacji należy użyć.
Można też wskazać, czy elementy i atrybuty zadeklarowane w schemacie lokalnie przy użyciu przestrzeni nazw muszą być kwalifikowane. Widzieliśmy już w schematach elementy i atrybuty zadeklarowane globalnie - deklaruje się je na najwyższym poziomie schematu, zaraz w elemencie schema. Wszystkie inne elementy i atrybuty deklarowane w schemacie są lokalne. W schematach możesz zapisać, czy deklaracje lokalne muszą być podczas używania w dokumencie kwalifikowane.
Definicje lokalne niekwalifikowane
Badanie działania schematów z przestrzeniami docelowymi i definicjami lokalnymi zaczniemy od definicji lokalnych niekwalifikowanych (których nie trzeba kwalifikować w dokumencie). Aby wskazać, czy elementy muszą być kwalifikowane, czy nie, używa się atrybutu elementFormDefault elementu schema. W przypadku atrybutów używa się atrybutu attributeFormDefault tego samego elementu. Wartością obu tych atrybutów może być albo słowo qualified, albo unqualified.
Czas na przykład, który pozwoli się zorientować, jak to działa. Przestrzenią docelową schematu będzie http://www.starpowder.com/namespace, użyjemy też przestrzeni http://www.w3.org/1999/XMLSchema, która będzie przestrzenią domyślną dokumentu, dzięki czemu można będzie pisać bezpośrednio annotation czy complexType, bez kwalifikowania przedrostkiem xsd.
Trzeba jednak pamiętać o rzeczy następującej: kiedy procesor XML będzie przetwarzał sprawdzany schemat i natknie się na przykład na typ złożony typTransakcja, będzie musiał odnaleźć odpowiednią przestrzeń nazw, a typu typTransakcja nie będzie przecież w przestrzeni domyślnej, którą jest przestrzeń schematów. Dlatego właśnie utworzymy nowy przedrostek przestrzeni t i skojarzymy go z domyślną przestrzenią nazw. Teraz wszystkie typy nie należące do przestrzeni samych schematów możemy poprzedzić przedrostkiem t:, aby procesor XML wiedział, w której przestrzeni nazw wyszukiwać ich definicji.
W naszym przykładzie zaznaczymy, że nie mają być kwalifikowane ani elementy, ani atrybuty. Oto jak wygląda nasz nowy schemat (zwróć uwagę, że przedrostkiem t poprzedzamy typy definiowane w tym schemacie, a nie używamy już tego przedrostka do typów należących do przestrzeni nazw schematów XML):
<schema xmlns="http://www.w3.org/1999/XMLSchema"
xmlns:t="http://www.starpowder.com/namespace"
targetNamespace="http://www.starpowder.com/namespace"
elementFormDefault="unqualified"
attributeFormDefault="unqualified">
<annotation>
<documentation>
Schemat opisujący pożyczenie książek.
</documentation>
</annotation>
<element name="transakcja" type="t:typTransakcja"/>
<complexType name="typTransakcja">
<element name="właściciel" type="t:adres"/>
<element name="wypożyczający" type="t:adres"/>
<element ref="uwagi" minOccurs="0"/>
<element name="książki" type="t:books"/>
<attribute name="dataWypożyczenia" type="date"/>
</complexType>
<element name="uwagi" type="string"/>
<complexType name="adres">
<element name="nazwisko" type="string"/>
<element name="ulica" type="string"/>
<element name="miasto" type="string"/>
<element name="stan" type="string"/>
<attribute name="telefon" type="string"
use="optional"/>
</complexType>
<complexType name=„typKsiążka”>
<element name="książka" minOccurs="0" maxOccurs="10">
<complexType>
<element name="tytuł" type="string"/>
<element name="dataWydania" type="date" minOccurs='0'/>
<element name="wartość" type="decimal"/>
<element name="terminMaksymalny">
<simpleType base="integer">
<maxExclusive value="14"/>
</simpleType>
</element>
<attribute name="IDksiążki" type="t:IDKatalogu"/>
</complexType>
</element>
</complexType>
<simpleType name="IDKatalogu" base="string">
<pattern value="\d{3}-\d{4}-\d{3}"/>
</simpleType>
</schema>
Jak zatem powinien wyglądać dokument zgodny z naszym schematem? Oto przykład - elementy definiowane lokalnie nie są kwalifikowane, ale elementy globalne, takie jak transakcja, uwagi czy książki już muszą być kwalifikowane. Zauważ też, przestrzeń nazw tego dokumentu jest taka sama jak przestrzeń docelowa schematu opisującego składnie tego dokumentu, i tak być powinno.
<?xml version="1.0" encoding="iso-8859-2"?>
<at:transakcja xmlns:at="http://www.starpowder.com/namespace"
dataWypożyczenia="2001-10-15">
<właściciel telefon="607.555.2222">
<nazwisko>Doug Glass</nazwisko>
<ulica>416 Disk Drive</ulica>
<miasto>Medfield</miasto>
<stan>MA</stan>
</właściciel>
<wypożyczający telefon="310.555.1111">
<nazwisko>Britta Regensburg</nazwisko>
<ulica>219 Union Drive</ulica>
<miasto>Medfield</miasto>
<stan>CA</stan>
</wypożyczający>
<at:uwagi>Właściciel żąda zwrotu książki w ciągu dwóch tygodni!</at:uwagi>
<at:książki>
<książka IDksiążki="123-4567-890">
<tytuł>Trzęsienia ziemi na dzień dobry</tytuł>
<dataWydania>2001-10-20</dataWydania>
<wartość>15.95</wartość>
<terminMaksymalny>14</terminMaksymalny>
</książka>
.
.
.
</at:książki>
</at:transakcja>
Użycie kwalifikowanych definicji lokalnych
Można też zażądać kwalifikowania definicji lokalnych. Oto przykładowy schemat, w którym żąda się, aby nazwy elementów były kwalifikowane:
<schema xmlns="http://www.w3.org/1999/XMLSchema"
xmlns:t="http://www.starpowder.com/namespace"
targetNamespace="http://www.starpowder.com/namespace"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<annotation>
<documentation>
Schemat opisujący pożyczenie książek.
</documentation>
</annotation>
.
.
.
Oto przykład dokumentu zgodnego z powyższym schematem - tym razem konieczne było jawne kwalifikowanie wszystkich elementów:
<?xml version="1.0" encoding="iso-8859-2"?>
<at:transakcja xmlns:at="http://www.starpowder.com/namespace"
dataWypożyczenia="2001-10-15">
<at:właściciel telefon="607.555.2222">
<at:nazwisko>Doug Glass</at:nazwisko>
<at:ulica>416 Disk Drive</at:ulica>
<at:miasto>Medfield</at:miasto>
<at:stan>MA</at:stan>
</at:właściciel>
<at:wypożyczający telefon="310.555.1111">
<at:nazwisko>Britta Regensburg</at:nazwisko>
<at:ulica>219 Union Drive</at:ulica>
<at:miasto>Medfield</at:miasto>
<at:stan>CA</at:stan>
</at:wypożyczający>
<at:uwagi>Właściciel żąda zwrotu książki w ciągu dwóch tygodni!</at:uwagi>
<at:książki>
<at:książka IDksiążki="123-4567-890">
<at:tytuł>Trzęsienia ziemi na dzień dobry</at:tytuł>
<at:dataWydania>2001-10-20</at:dataWydania>
<at:wartość>15.95</at:wartość>
<at:terminMaksymalny>14</at:terminMaksymalny>
</at:książka>
.
.
.
</at:książki>
</at:transakcja>
Innym sposobem tworzenia dokumentów zgodnych z takim schematem jest zastąpienie jawnego kwalifikowania wszystkich elementów kwalifikowaniem niejawnym przez użycie domyślnej przestrzeni nazw. Oto jak to wygląda:
<?xml version="1.0" encoding="iso-8859-2"?>
<transakcja xmlns=http://www.starpowder.com/namespace"
dataWypożyczenia="2001-10-15">
<właściciel telefon="607.555.2222">
<nazwisko>Doug Glass</nazwisko>
<ulica>416 Disk Drive</ulica>
<miasto>Medfield</miasto>
<stan>MA</stan>
</właściciel>
<wypożyczający telefon="310.555.1111">
<nazwisko>Britta Regensburg</nazwisko>
<ulica>219 Union Drive</ulica>
<miasto>Medfield</miasto>
<stan>CA</stan>
</wypożyczający>
<uwagi>Właściciel żąda zwrotu książki w ciągu dwóch tygodni!</uwagi>
<książki>
<książka IDksiążki="123-4567-890">
<tytuł>Trzęsienia ziemi na dzień dobry</tytuł>
<dataWydania>2001-10-20</dataWydania>
<wartość>15.95</wartość>
<terminMaksymalny>14</terminMaksymalny>
</książka>
.
.
.
</książki>
</transakcja>
Jak dotąd wymuszaliśmy kwalifikowanie bądź nie wszystkich elementów lokalnych. Można jednak za pomocą atrybutu form wprowadzić rozróżnienie co do kwalifikowania bądź nie.
Oto przykład, w którym pozwalamy nie kwalifikować wszystkich definicji lokalnych za wyjątkiem atrybutu IDksiążki:
<schema xmlns="http://www.w3.org/1999/XMLSchema"
xmlns:t="http://www.starpowder.com/namespace"
targetNamespace="http://www.starpowder.com/namespace"
elementFormDefault="unqualified"
attributeFormDefault="unqualified">
<annotation>
<documentation>
Schemat opisujący pożyczenie książek.
</documentation>
</annotation>
<element name="transakcja" type="t:typTransakcja"/>
<complexType name="typTransakcja">
<element name="właściciel" type="t:adres"/>
<element name="wypożyczający" type="t:adres"/>
<element ref="uwagi" minOccurs="0"/>
<element name="książki" type="t:books"/>
<attribute name="dataWypożyczenia" type="date"/>
</complexType>
<element name="uwagi" type="string"/>
<complexType name="adres">
<element name="nazwisko" type="string"/>
<element name="ulica" type="string"/>
<element name="miasto" type="string"/>
<element name="stan" type="string"/>
<attribute name="telefon" type="string"
use="optional"/>
</complexType>
<complexType name=„typKsiążka”>
<element name="książka" minOccurs="0" maxOccurs="10">
<complexType>
<element name="tytuł" type="string"/>
<element name="dataWydania" type="date" minOccurs='0'/>
<element name="wartość" type="decimal"/>
<element name="terminMaksymalny">
<simpleType base="integer">
<maxExclusive value="14"/>
</simpleType>
</element>
<attribute name="IDksiążki" type="t:IDKatalogu"
form="qualified"/>
</complexType>
</element>
</complexType>
<simpleType name="IDKatalogu" base="string">
<pattern value="\d{3}-\d{4}-\d{3}"/>
</simpleType>
</schema>
Oto dokument z powyższym schematem zgodny. Wszystkie definicje lokalne za wyjątkiem atrybutu IDksiążki nie są kwalifikowane:
<?xml version="1.0" encoding="iso-8859-2"?>
<transakcja xmlns=http://www.starpowder.com/namespace"
dataWypożyczenia="2001-10-15">
<właściciel telefon="607.555.2222">
<nazwisko>Doug Glass</nazwisko>
<ulica>416 Disk Drive</ulica>
<miasto>Medfield</miasto>
<stan>MA</stan>
</właściciel>
<wypożyczający telefon="310.555.1111">
<nazwisko>Britta Regensburg</nazwisko>
<ulica>219 Union Drive</ulica>
<miasto>Medfield</miasto>
<stan>CA</stan>
</wypożyczający>
<uwagi>Właściciel żąda zwrotu książki w ciągu dwóch tygodni!</uwagi>
<książki>
<książka at:IDksiążki="123-4567-890">
<tytuł>Trzęsienia ziemi na dzień dobry</tytuł>
<dataWydania>2001-10-20</dataWydania>
<wartość>15.95</wartość>
<terminMaksymalny>14</terminMaksymalny>
</książka>
.
.
.
</książki>
</transakcja>
Możliwości schematów są znacznie większe niż to tutaj opisano. Schematy mogą na przykład nawzajem po sobie dziedziczyć, tak jak w językach obiektowych, można też owo dziedziczenie ograniczać. Schematy XML są nadal rozwijającym się standardem - pozostaje mieć tylko nadzieję, że ów rozwój nie przekroczy możliwości autorów procesorów XML i że już wkrótce pojawią się procesory obsługujące schematy przynajmniej częściowo.
fixed możemy traktować jako deklarację stałej.
34 Część I ♦ Podstawy obsługi systemu WhizBang (Nagłówek strony)
Rozdział 1 ♦ Pierwsze kroki (Nagłówek strony)
34 C:\Moje dokumenty\Wojtek Romowicz\Książki\XML Vademecum profesjonalisty\r03-01.doc
C:\Moje dokumenty\Wojtek Romowicz\Książki\XML Vademecum profesjonalisty\r03-01.doc 1