Standard XML Schema zdefiniowany jest w trzech rekomendacjach:
Istnieje też tutorial W3 Schools po XML Schema...
XML Schema sam jest zastosowaniem XML, to znaczy schematy są
dokumentami XML.
Elementy XML Schema znajdują się w przestrzeni nazw
http://www.w3.org/2001/XMLSchema
,
w schematach zwykło się używać dla niej prefiksów
xs
lub xsd
.
Standardowym rozszerzeniem nazwy dla pliku ze schematem jest
xsd
.
W schemacie na najwyższym poziomie, tzn. jako dzieci elementu
głównego schema
, występują definicje:
Ponadto na początku dokumentu mogą wystąpić elementy związane z łączeniem wielu schematów, a w dowolnym miejscu anotacje, m.in. dokumentacja schematu (opisy elementów, atrybutów, typów itd.).
W schematach elementom i atrybutom o różnych nazwach przypisuje się typ zawartości. Można to zrobić w poniższy sposób, odwołując się do typu nazwanego.
Plik: osoby1.xsd.
<xs:element name="osoba" type="OsobaTyp"/> <xs:element name="imie" type="xs:string"/> <xs:element name="nazwisko" type="xs:string"/> <xs:attribute name="plec" type="PlecTyp"/> <xs:attribute name="email" type="xs:string"/>
W XML Schema istnieją typy predefiniowane, m.in. występujący w
przykładzie string
.
Nazwy tych typów znajdują się w przestrzeni nazw XML Schema i dlatego
nazwa jest poprzedzona prefiksem.
Własne typy nazwane można zdefiniować w poniższy sposób, nieco odmienny dla typów prostych i złożonych.
Plik: osoby1.xsd.
<xs:complexType name="OsobaTyp"> <xs:sequence> <xs:element ref="imie" minOccurs="1" maxOccurs="unbounded"/> <xs:element ref="nazwisko"/> </xs:sequence> <xs:attribute ref="plec" use="required"/> <xs:attribute ref="email" use="optional"/> </xs:complexType> <xs:simpleType name="PlecTyp"> <xs:restriction base="xs:string"> <xs:enumeration value="k"/> <xs:enumeration value="m"/> </xs:restriction> </xs:simpleType>
Typów nazwanych należy używać wtedy, gdy wiele elementów / atrybutów posiada ten sam typ zawartości. Tylko typy nazwane mogą stanowić podstawę do rozszerzania bądź zawężania (więcej na przyszłych zajęciach).
Definicję typu można umieścić też wewnątrz definicji elementu (lub atrybutu). Wówczas mamy do czynienia z typem anonimowym.
Plik: osoby2.xsd.
<xs:element name="osoba"> <xs:complexType> <xs:sequence> <xs:element ref="imie" minOccurs="1" maxOccurs="unbounded"/> <xs:element ref="nazwisko"/> </xs:sequence> <xs:attribute ref="plec" use="required"/> <xs:attribute ref="email" use="optional"/> </xs:complexType> </xs:element> <xs:attribute name="plec"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:enumeration value="k"/> <xs:enumeration value="m"/> </xs:restriction> </xs:simpleType> </xs:attribute>
Typów anonimowych należy używać tylko wtedy, gdy tylko jeden element / atrybut posiada dany typ zawartości i nie przewidujemy dodania do schematu nowych elementów / atrybutów z takim typem.
Typy złożone definiuje się elementem schematu
complexType
.
Typ złożony, w odróżnieniu od typu prostego, może posiadać wewnętrzną
strukturę: podelementy i atrybuty.
Dlatego tylko elementom (a nie atrybutom) można przypisywać typy złożone.
W definicji typu złożonego T określa się jakie podelementy i atrybuty może zawierać element o typie T. Ponadto dla podelementów określa się ich kolejność i dopuszczalne krotności, a dla atrybutów ich opcjonalność. Dla atrybutów oraz elementów o zawartości prostej można podać wartości domyślne (brane pod uwagę tylko przez procesory walidujące dokument względem schematu).
Na przykład elementy o poniższym typie mogą zawierać dowolną
niezerową liczbę elementów
imie
, a następnie dokładnie jeden element
nazwisko
. Poza tym element musi mieć atrybut
plec
i może mieć atrybut email
.
Atrybuty i elementy są zdefiniowane gdzieś indziej w schemacie
(stąd atrybut ref
).
<xs:complexType name="OsobaTyp"> <xs:sequence> <xs:element ref="imie" minOccurs="1" maxOccurs="unbounded"/> <xs:element ref="nazwisko" minOccurs="1" maxOccurs="1"/> </xs:sequence> <xs:attribute ref="plec" use="required"/> <xs:attribute ref="email" use="optional"/> </xs:complexType>
Domyślną liczbą wystąpień podelementu jest dokładnie 1, a atrybuty domyślnie są opcjonalne.
Element schematu
sequence
, użyty w poprzednim przykładzie,
grupuje podelementy w sekwencję. Istnieją trzy elementy schematu służące
do konstruowania takich grup elementów:
sequence
– w dokumencie muszą występować wszystkie podane podelementy
w tej samej kolejności,choice
–
w dokumencie musi wystąpić dokładnie jeden z wymienionych
podelementów (w takiej liczbie, jaka jest zgodna
z jego minOccurs
i maxOccurs
),
all
–
w dokumencie muszą występować wszystkie podane podelementy, ale w dowolnej kolejności;
w tym przypadku dla podelementów musi zachodzić maxOccurs <= 1
.
Sekwencje i wybory można w sobie zagnieżdżać, konstruując bardziej
skomplikowane typy zawartości.
W zagnieżdżeniach nie mogą brać udziału grupy
all
.
Plik: przyklad1.xsd.
<xs:complexType name="typ1"> <!-- Dokładnie jeden element A lub od 2 do 3 elementów B. --> <xs:choice> <xs:element ref="A"/> <xs:element ref="B" minOccurs="2" maxOccurs="3"/> </xs:choice> </xs:complexType> <xs:complexType name="typ2"> <!-- Dokładnie jeden element Start, następnie dowolna liczba wystąpień grup, z których każda jest parą elementów A albo parą elementów B i C, na końcu dokładnie jeden element Koniec. --> <xs:sequence> <xs:element ref="Start"/> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="A" minOccurs="2" maxOccurs="2"/> <xs:sequence> <xs:element ref="B"/> <xs:element ref="C"/> </xs:sequence> </xs:choice> <xs:element ref="Koniec"/> </xs:sequence> </xs:complexType>
Otwórz w widoku tekstowym ten schemat. Spróuj zdefiniować następujące typy zawartości:
A
, następnie dokładnie jeden element
B
i opcjonalny element C
.
A
, dwoma elementami B
lub trzeba elementami C
,
A
,
A
, B
i opcjonalny element C
,
w dowolnej kolejności,
A
, jeden element B
i opcjonalny element C
,
wszystko w dowolnej kolejności.
Wyjaśnienie: XML Schema wymaga aby typy zawartości w schemacie
były deterministyczne.
W grupach typu all
elementy mogą występować najwyżej jeden raz.
Open this schema in Eclipse, go to the source view.
Try to define new elements with the given content types:
A
, then exactly one
B
and optional
C
.
A
,
two elements B
, or three elements C
,
A
,
A
,
B
, and optional element C
, in any order,
A
, one element B
, and optional element
C
, in any order.
Model zawartości zdefiniowany w XML Schema musi być deterministyczny . Problem ten jest opisany w rekomendacjach w następujących miejscach:
Intuicyjnie determinizm polega na tym, że dla każdego dokumentu podczas czytania dokumentu po napotkaniu początku kolejnego elementu parser jest w stanie jednoznacznie wskazać pozycję w schemacie (lub DTD), która temu elementowi odpowiada, bez analizowania kolejnych elementów.
Wiele modeli zapisanych niedeterministycznie daje się zapisać deterministycznie. Na przykład (notacja z DTD):
(a,b)|(a,c)
można zapisać jako
a,(b|c)
,
Istnieją jednak modele zawartości, których nie da się wyrazić deterministycznie, np.:
(a,b)*,a?
,
(aa)*|(aaa)*
z zadania.
Zdefiniuj w XML Schema strukturę elementów towar
i zamówienie
związanych z obsługą sklepu.
W miejscach, gdzie należy użyć typów prostych, użyj typu string
lub ewentualnie jednego z predefiniowanych typów XML Schema (do szczegółów
typów prostych przejdziemy na następnych zajęciach).
Modelowane elementy:
In XML Schema, define structure for elements related to
Wygeneruj przykładowy katalog towarów oraz przykładowe zamówienie (i wzbogać o przykładowe dane).
Generate (with Eclipse) and fill with example data a shop catalogue and an order.
Gdy jakaś grupa (sekwencja, wybór lub
all
) powtarza się w wielu miejscach (np. w różnych definicjach typu),
można w jednym miejscu zdefiniować nazwaną
grupę elementów, a w definicjach typów
odwoływać się do tej grupy.
W schemacie
figury1.xsd
występują powtarzające się sekwencje elementów
x
i y
. W schemacie
figury2.xsd
zostały zastąpione grupą współrzędne
,
jak poniżej.
<xs:group name="współrzędne"> <xs:sequence> <xs:element name="x" type="xs:double"/> <xs:element name="y" type="xs:double"/> </xs:sequence> </xs:group> <xs:element name="odcinek"> <xs:complexType> <xs:sequence> <xs:group ref="współrzędne" minOccurs="2" maxOccurs="2"/> </xs:sequence> <xs:attributeGroup ref="atrybuty-krawędzi"/> </xs:complexType> </xs:element>
Podobnie jak grupy elementów, można także zdefiniować grupy atrybutów i odwoływać się do nich w definicjach typów.
W schemacie
figury1.xsd
występują powtarzające się atrybuty
kolor-krawędzi
,
grubość-krawędzi
i kolor-powierzchni
. W schemacie
figury2.xsd
zostały zastąpione grupami atrybutów
atrybuty-krawędzi
im atrybuty-powierzchni
,
jak poniżej.
<xs:attributeGroup name="atrybuty-krawędzi"> <xs:attribute name="kolor-krawędzi" type="KolorTyp"/> <xs:attribute name="grubość-krawędzi" type="xs:positiveInteger"/> </xs:attributeGroup> <xs:element name="punkt"> <xs:complexType> <xs:sequence> <xs:group ref="współrzędne" minOccurs="1" maxOccurs="1"/> </xs:sequence> <xs:attributeGroup ref="atrybuty-krawędzi"/> </xs:complexType> </xs:element>
W XML węzły tekstowe mogą występować obok węzłów elementów jako
dzieci tego samego elementu.
W tekstowej reprezentacji XML można to opisać jako
tekst z zanurzonymi elementami
albo
znakowany tekst
.
Typ zawartości, który dopuszcza tekst z zanurzonymi elementami,
nazywa się
typem mieszanym
(mixed content type)
i można go zdefiniować w XML Schema. Służy do tego atrybut
mixed
w elemencie complexType
.
Włączenie typu mieszanego pozwala na pojawienie się węzłów tekstowych pomiędzy podelementami. Ważne jest to, że liczba i kolejność podelementów nadal jest kontrolowana zgodnie z definicją typu (inaczej niż w DTD). Nie jest natomiast kontrolowany tekst i nie da się go ograniczyć typem prostym (np. do liczb).
Poniższe przykłady pochodzą z rekomendacji XML Schema.
<xsd:element name="letterBody"> <xsd:complexType mixed="true"> <xsd:sequence> <xsd:element name="salutation"> <xsd:complexType mixed="true"> <xsd:sequence> <xsd:element name="name" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="quantity" type="xsd:positiveInteger"/> <xsd:element name="productName" type="xsd:string"/> <xsd:element name="shipDate" type="xsd:date" minOccurs="0"/> <!-- etc. --> </xsd:sequence> </xsd:complexType> </xsd:element>
<letterBody> <salutation>Dear Mr.<name>Robert Smith</name>.</salutation> Your order of <quantity>1</quantity> <productName>Baby Monitor</productName> shipped from our warehouse on <shipDate>1999-05-21</shipDate>. .... </letterBody>
Wzbogać opisy tekstowe towarów o elementy znakujące, np. wyróżnienie, odnośnik do URL, odnośnik do innego towaru.
Enrich text descriptions of articles with „formatting tags” such as emphasis or hyperlink.
Elementy i atrybuty można definiować na głównym poziomie schematu i
odwoływać się do nich w definicjach typów
w atrybucie
ref
.
Takie podejście jest zalecane dla elementów i atrybutów, które występują w wielu typach, zawsze z tym samym typem zawartości. Tylko element zdefiniowany globalnie (i każdy taki element) może być elementem głównym dokumentu.
Przykładami schematów napisanych w ten sposób są osoby1.xsd , osoby2.xsd i przyklad2.xsd .
Elementy i atrybuty można także definiować lokalnie, wewnątrz
definicji typu (nazwanego lub anonimowego).
Definicje można zagnieżdżać. Nazwę podaje się wówczas w atrybucie
name
.
Takie podejście jest zalecane dla elementów i atrybutów, które występują tylko w jednym miejscu schematu lub w różnych miejscach schematu mają różny typ zawartości (patrz poniższy podrozdział). Definiując element lokalnie można także wymusić, aby nie był elementem głównym dokumentu.
Przykładami schematów napisanych w ten sposób są osoby3.xsd , osoby4.xsd i przyklad3.xsd .
Schemat jest bardziej czytelny, gdy definicje nie są zbytnio zagnieżdżone (chociaż to może kwestia gustu). Dlatego lepiej, aby lokalne definicje elementów / atrybutów (w jakimś typie) same nie zawierały już skomplikowanego typu anonimowego, a najlepiej odwoływały się do typu nazwanego.
Lokalna definicja elementu / atrybutu obowiązuje tylko w miejscu jej wystąpienia. W innym miejscu schematu można zdefiniować element / atrybut o tej samej nazwie, ale o innym typie zawartości.
Na przykład w schemacie
przyklad2.xsd
element
c
zdefiniowany jest globalnie, w każdym miejscu posiada ten sam typ
zawartości: liczby całkowite dodatnie.
Dokument
przyklad2.xml
jest zgodny z tym schematem.
Natomiast w schemacie
przyklad3.xsd
element
c
zdefiniowany jest lokalnie dwa razy.
c
położone wewnątrz elementów
a
mogą zawierać
liczby dodatnie, natomiast
c
położone wewnątrz elementów
b
mogą zawierać liczby ujemne.
Dokument
przyklad2.xml
nie jest zgodny z tym schematem, natomiast
zgodny jest dokument
przyklad3.xml
.
Stosowanie lokalnych definicji z (potencjalnie) różnym typem
zawartości może być zaletą.
Dzięki temu możemy stosować te same nazwy, jeśli są naturalne w danym
miejscu.
Element
kod
wewnątrz artykułu może
oznaczać kod źródłowy, a wewnątrz adresu kod pocztowy. Dzięki XML Schema
możemy dla
takich elementów podać różne typy zawartości (nie użwając różnych
przestrzeni nazw przestrzeni nazw).
Jednak nadawanie różnego znaczenia i różnego typu zawartości elementom o tej samej nazwie może prowadzić do niejednoznaczności i utrudniać rozumienie schematu oraz odczytywanie informacji z dokumentu. Dlatego tej techniki można używać tylko w naprawdę uzasadnionych sytuacjach.
W pełni uzasadnione jest lokalne definiowanie atrybutów, gdyż ich znaczenie (i typ zawartości) są ściśle związane z elementem, w którym występują. Jednak w przypadku atrybutów, które występują w wielu elementach (typach zawartości) w tym samym znaczeniu, zalecane jest ich globalne definiowanie.
Pozostaw jako elementy globalne jedynie te, które mają sens jako elementy główne: katalog, towar, zamówienie. Pozostałe „ukryj” wewnątrz grup lub typów złożonych.
Make only the following elements global: catalogue, article, order. „Hide” definitions of the rest of elements within named groups or complex types (either named or anonymous).