Pro rychlé vpravení do problematiky si rovnou ukážeme jednoduchý příklad Relax NG schématu a dokumentu XML, který mu vyhovuje. Dejme tomu, že chceme vytvořit schéma popisující dokumenty XML vhodné pro přenos informace o jednom zaměstnanci. U zaměstnance nás přitom bude zajímat jeho identifikační číslo, jméno, příjmení, plat a datum narození. Tyto informace můžeme v XML zachytit následujícím způsobem:
<zamestnanec id="101"> <jmeno>Jan</jmeno> <prijmeni>Novák</prijmeni> <plat>25000</plat> <narozen>1965-12-24</narozen> </zamestnanec>
Odpovídající schéma tedy musí definovat, že dokument musí
obsahovat element zamestnanec
, který obsahuje
atribut id
a čtyři podelementy
jmeno
, prijmeni
,
plat
a narozen
. Tyto
požadavky může zachytit následující jednoduché schéma.
r
n
g<element xmlns="http://relaxng.org/ns/structure/1.0" name="zamestnanec"> <attribute name="id"> <text/> </attribute> <element name="jmeno"> <text/> </element> <element name="prijmeni"> <text/> </element> <element name="plat"> <text/> </element> <element name="narozen"> <text/> </element> </element>
Vidíme, že celé schéma je dokument XML, který používá speciální
elementy. Všechny tyto elementy musí patřit do jmenného prostoru
http://relaxng.org/ns/structure/1.0
. Schéma tak
můžeme atlernativně zapsat i s využitím prefixů.
r
n
g<rng:element xmlns:rng="http://relaxng.org/ns/structure/1.0" name="zamestnanec"> <rng:attribute name="id"> <rng:text/> </rng:attribute> <rng:element name="jmeno"> <rng:text/> </rng:element> <rng:element name="prijmeni"> <rng:text/> </rng:element> <rng:element name="plat"> <rng:text/> </rng:element> <rng:element name="narozen"> <rng:text/> </rng:element> </rng:element>
Zatímco WXS jsou založena na datových typech, je Relax NG založeno na vzorech. Celé schéma je vzorem dokumentu. Vzor se přitom skládá ze vzorů pro elementy, atributy a textové uzly. Tyto vzory pak mohou být dále kombinovány do uspořádaných i neuspořádaných skupin, mohou být volitelné a může u nich být určen počet opakování. Tento jednoduchý princip umožňuje velmi jednoduše vyjádřit i složité struktury v dokumentu a navíc je založen na solidním matematickém základu alejových gramatik (hedge grammars).
Kouzelnou vlastností Relax NG je kompaktní syntaxe. Ta umožňuje zapsat schéma v textové syntaxi, která je mnohem úspornější než ta založená na XML.
r
n
celement zamestnanec {
attribute id { text },
element jmeno { text },
element prijmeni { text },
element plat { text },
element narozen { text }
}
V dalším textu budeme většinu ukázek zapisovat paralelně v obou syntaxích. Záleží na vás, kterou z nich si pak vyberete pro vaše použití. Někomu více vyhovuje upovídanější syntaxe XML, někomu zase spíše ta kompaktní textová. Je však úplně jedno jakou syntaxi zvolíte, protože jsou mezi sebou navzájem převoditelné.
Jak jsme si již řekli, celé schéma v Relax NG se skládá ze vzorů. Podívejme se proto na základní vzory a jejich použití.
Tomuto vzoru vyhoví jakýkoliv text (i prázdný), používá se pro definici obsahu elementů, které už neobsahují další podelementy, nebo pro definici obsahu atributů.
r
n
g<text/>
r
n
ctext
Vzoru pro atribut vyhovují atributy uvedené v dokumentu
XML. Jméno atributu se určuje pomocí atributu name
a obsah atributu pak obsahem vzoru
attribute
. Atributy nejde dále strukturovat,
proto se pro ně nejčastěji používá vzor text
, ale
dále si ukážeme, jak lze použít i jiné datové typy.
r
n
g<attribute name="měna"> <text/> </attribute>
Protože atributy vždy obsahují nějaký text, může se při jejich
definici vynechat vzor text
. Předchozí příklad jde
tedy zapsat také jako
r
n
g<attribute name="měna"/>
V kompaktní syntaxi takové vynechání definice typu atributu není možné.
r
n
cattribute měna { text }
Vzoru pro element samozřejmě vyhovují elementy. Podobně jako
u atributu musíme pomocí atributu name
určit jméno elementu. Obsah elementu
je pak určen dalšími vzory, které se píší dovnitř definice
elementu. Například element, který umožňuje uložení jména, můžeme
deklarovat jako:
r
n
g<element name="jméno"> <text/> </element>
r
n
celement jméno { text }
Elementy mohou obsahovat atributy. Do vzoru pro elementy proto můžeme přidávat více vzorů, včetně vzorů pro atributy. Např. zápis ceny doplněné o kód měny:
<cena měna="USD">29.95</cena>
Můžeme ve schématu definovat jako:
r
n
g<element name="cena"> <attribute name="měna"/> <text/> </element>
r
n
celement cena {
attribute měna { text },
text
}
V definici elementu se může vzor pro atributy vyskytovat kdekoliv, nemusí být jen na začátku. Následující schéma je tak totožné s předchozím příkladem.
r
n
g<element name="cena"> <text/> <attribute name="měna"/> </element>
r
n
celement cena {
text,
attribute měna { text }
}
Element může samozřejmě obsahovat podelementy. Ve schématu to zapíšeme tak, že do definice elementu vložíme vzory pro podelementy. Pro dokument:
<osoba narozen="1.1.1970"> <jméno>Jan</jméno> <příjmení>Novák</příjmení> <email>jan.novak@example.com</email> </osoba>
tak můžeme použít následující schéma
r
n
g<element name="osoba"> <element name="jméno"> <text/> </element> <element name="příjmení"> <text/> </element> <element name="email"> <text/> </element> <attribute name="narozen"/> </element>
r
n
celement osoba {
element jméno { text },
element příjmení { text },
element email { text },
attribute narozen { text }
}
V praxi se často setkáme s požadavkem, aby nějaký
atribut, element či celá skupina elementů byla nepovinná.
V dokumentu se tedy objevit může, ale nemusí. RELAX NG tento
požadavek řeší velmi elegantně. Jakýkoliv jiný vzor lze obalit vzorem
optional
, který říká, že vzor v něm obsažený
se nemusí v dokument objevit.
Chceme-li, aby v předchozím příkladě bylo možné vynechat
e-mailovou adresu nebo datum narození, stačí vzory pro odpovídající
elementy a atributy zabalit do optional
.
r
n
g<element name="osoba"> <element name="jméno"> <text/> </element> <element name="příjmení"> <text/> </element> <optional> <element name="email"> <text/> </element> </optional> <optional> <attribute name="narozen"/> </optional> </element>
V kompaktní syntaxi se volitelnost vyjadřuje znakem
„?
“ zapsaným za konec vzoru. Syntaxe
tak připomíná DTD nebo regulární výrazy.
r
n
celement osoba {
element jméno { text },
element příjmení { text },
element email { text }?,
attribute narozen { text }?
}
Tomuto schématu pak kromě původního schématu vyhoví i následující dokumenty:
<osoba> <jméno>Jan</jméno> <příjmení>Novák</příjmení> </osoba>
<osoba narozen="1.1.1970"> <jméno>Jan</jméno> <příjmení>Novák</příjmení> </osoba>
<osoba> <jméno>Jan</jméno> <příjmení>Novák</příjmení> <email>jan.novak@example.com</email> </osoba>
Volitelný vzor se vždy chápe jako jeden celek. Následující schéma má proto úplně jiný význam, i když to na první pohled nemusí být patrné.
r
n
g<element name="osoba"> <element name="jméno"> <text/> </element> <element name="příjmení"> <text/> </element> <optional> <element name="email"> <text/> </element> <attribute name="narozen"/> </optional> </element>
r
n
celement osoba {
element jméno { text },
element příjmení { text },
(element email { text },
attribute narozen { text })?
}
Volitelný je nyní vzor, který obsahuje atribut narozen
a element
email
. Oba dva proto musí zároveň buď chybět, nebo
být přítomné. Bude-li uveden jen atribut narozen
, nebo element
email
, nebude dokument validní. Následující dva
dokumenty jsou příklady dokumentů, které schématu nevyhovují.
<osoba narozen="1.1.1970"> <jméno>Jan</jméno> <příjmení>Novák</příjmení> </osoba>
<osoba> <jméno>Jan</jméno> <příjmení>Novák</příjmení> <email>jan.novak@example.com</email> </osoba>
Vzor oneOrMore
říká, že jeho obsah se může
v dokumentu opakovat vícekrát. Můžeme tak například snadno
definovat, že jedna osoba může mít více emailových adres.
<osoba narozen="1.1.1970"> <jméno>Jan</jméno> <příjmení>Novák</příjmení> <email>jan.novak@example.com</email> <email>jenda@example.org</email> </osoba>
V odpovídajícím schématu je definice elementu
email
obalena vzorem
oneOrMore
.
r
n
g<element name="osoba"> <element name="jméno"> <text/> </element> <element name="příjmení"> <text/> </element> <oneOrMore> <element name="email"> <text/> </element> </oneOrMore> <attribute name="narozen"/> </element>
V kompaktní syntaxi se opakovaní vzoru zapisuje pomocí znaku
„+
“:
r
n
celement osoba {
element jméno { text },
element příjmení { text },
element email { text }+,
attribute narozen { text }
}
Chceme-li, aby se určitá část dokumentu mohla libovolněkrát
opakovat nebo úplně chybět, můžeme s výhodou použít vzor
zeroOrMore
. Chceme-li umožnit zadat libovolný počet
emailových adres, případně adresu vynechat, můžeme použít následující
schéma.
r
n
g<element name="osoba"> <element name="jméno"> <text/> </element> <element name="příjmení"> <text/> </element> <zeroOrMore> <element name="email"> <text/> </element> </zeroOrMore> <attribute name="narozen"/> </element>
r
n
celement osoba {
element jméno { text },
element příjmení { text },
element email { text }*,
attribute narozen { text }
}
Tomuto schématu pak vyhoví všechny následující varianty dokumentu.
<osoba narozen="1.1.1970"> <jméno>Jan</jméno> <příjmení>Novák</příjmení> </osoba>
<osoba narozen="1.1.1970"> <jméno>Jan</jméno> <příjmení>Novák</příjmení> <email>jenda@example.org</email> </osoba>
<osoba narozen="1.1.1970"> <jméno>Jan</jméno> <příjmení>Novák</příjmení> <email>jan.novak@example.com</email> <email>jenda@example.org</email> </osoba>
Vzory optional
, oneOrMore
a zeroOrMore
slouží k určení počtu opakování vzoru,
který obalují. Pokud žádný z těchto vzorů nepoužijeme, je počet
opakování jedna.
RELAX NG bohužel nenabízí prostředky pro snadný zápis situací,
kdy se nějaký vzor má opakovat a my chceme přesně určit jeho počet
opakování. Například chceme říci, že u jedné osoby chceme mít uvedena
nejméně dvě a nejvíce pět telefonních čísel. V WXS toho můžeme snadno
dosáhnout pomocí atributů minOccurs
a maxOccurs
. RELAX NG podobnou možnost
nenabízí, a proto tento požadavek musíme vyřešit tak, že dvě
telefonní čísla necháme povinná a další tři zadáme jako
volitelná.
r
n
g<element name="osoba"> <element name="jméno"> <text/> </element> <element name="telefon"> <text/> </element> <element name="telefon"> <text/> </element> <optional> <element name="telefon"> <text/> </element> </optional> <optional> <element name="telefon"> <text/> </element> </optional> <optional> <element name="telefon"> <text/> </element> </optional> </element>
r
n
celement osoba {
element jméno { text },
element telefon { text },
element telefon { text },
element telefon { text }?,
element telefon { text }?,
element telefon { text }?
}
Zvláště pro větší počty opakování složitějších vzorů je tento postup poměrně nepřehledný. Situaci si lze zjednodušit použitím pojmenovaných vzorů. V praxi si naštěstí velmi často vystačíme se vzory pro opakování, které nabízí RELAX NG. Další možností je pak použít vzor RELAX NG, který je méně restriktivní než náš požadavek a dodatečné požadavky na počet výskytů elementu vyjádřit pomocí doplňkového schématu ve Schematronu.
V následujícím schématu očekáváme, že uvnitř elementu
osoba
se budou vyskytovat podelementy
jméno
, příjmení
a
email
v pořadí, v jakém jsou uvedeny ve
schématu.
r
n
g<element name="osoba"> <element name="jméno"> <text/> </element> <element name="příjmení"> <text/> </element> <element name="email"> <text/> </element> <attribute name="narozen"/> </element>
Toto chování je zajištěno tím, že vzory uvnitř definice elementu
se obalí vzorem group
. Takže naše schéma je
ekvivalentní následujícímu schématu:
r
n
g<element name="osoba"> <group> <element name="jméno"> <text/> </element> <element name="příjmení"> <text/> </element> <element name="email"> <text/> </element> <attribute name="narozen"/> </group> </element>
Vzory uvedené uvnitř group
se musí
v dokumentu vyskytovat ve stejném pořadí, v jakém jsou
definovány ve schématu. Toto omezení se nevztahuje na atributy, které
mohou být ve vzoru kdekoliv, ale testují se samozřejmě
u počátečního tagu daného elementu.
V kompaktní syntaxi místo group
oddělíme
jednotlivé vzory čárkou.
Vzor group
se explicitně používá zejména
tehdy, když potřebujeme několik vzorů seskupit do jednoho pro další
použití ve vzorech jako je choice
.
Vzor choice
říká, že v dokumentu se může
vyskytovat právě jeden z vzorů uvedených uvnitř
choice
.
Dejme tomu, že chceme, aby se u osoby musel kromě jména zadat jeden z identifikátorů rodné číslo, číslo pasu nebo číslo sociálního pojištění. Tj. aby všechny tři následující dokumenty byly validní:
<osoba> <jméno>Pepa Tuzemec</jméno> <RČ>681203/0123</RČ> </osoba> <osoba> <jméno>Pepa Cizinec</jméno> <pas>1234567</pas> </osoba> <osoba> <jméno>Pepa Rozvědčík</jméno> <SSN>987654321</SSN> </osoba>
V tomto případě můžeme vyjádřit požadavek na výběr jednoho
z elementů právě pomocí choice
.
V kompaktní textové syntaxi se pak pro oddělení variant používá
znak „|
“.
r
n
g<element name="osoba"> <element name="jméno"> <text/> </element> <choice> <element name="RČ"> <text/> </element> <element name="pas"> <text/> </element> <element name="SSN"> <text/> </element> </choice> </element>
r
n
celement osoba {
element jméno { text },
(element RČ { text }
| element pas { text }
| element SSN { text })
}
Má-li být součástí jedné z variant více elementů nebo
atributů, musíme je obalit pomocí group
. Následující schéma umožňuje
u osoby zadat buď její jméno, nebo kombinaci křestního jména a
příjmení. Zároveň je potřeba zadat e-mailovou adresu, která může být
zadána jako element nebo atribut. Zde se s výhodou využívá toho,
že vzor pro atribut může být uveden kdekoliv v definici
elementu.
r
n
g<element name="osoba"> <choice> <element name="jméno"> <text/> </element> <group> <element name="křestní"> <text/> </element> <element name="příjmení"> <text/> </element> </group> </choice> <choice> <element name="email"> <text/> </element> <attribute name="email"/> </choice> </element>
r
n
celement osoba {
(element jméno { text }
| (element křestní { text },
element příjmení { text })),
(element email { text }
| attribute email { text })
}
Takovému schématu pak vyhoví například následující dokumenty:
<osoba> <jméno>Pepa</jméno> <email>pepan@example.com</email> </osoba> <osoba email="pepan@example.com"> <jméno>Pepa</jméno> </osoba> <osoba email="pepan@example.com"> <křestní>Pepa</křestní> <příjmení>Novák</příjmení> </osoba> <osoba> <křestní>Pepa</křestní> <příjmení>Novák</příjmení> <email>pepan@example.com</email> </osoba>
Naopak nevyhoví následující dokumenty, v nichž se vyskytuje nedovolená duplicita.
<osoba email="pepan@example.com"> <jméno>Pepa</jméno> <email>pepan@example.com</email> </osoba> <osoba email="pepan@example.com"> <jméno>Pepan</jméno> <křestní>Pepa</křestní> <příjmení>Novák</příjmení> </osoba>
V praxi se často setkáme s případy, kdy je nám
jedno, v jakém pořadí se nějaké elementy vyskytnou. Dejme tomu,
že chceme, aby se uvnitř elementu osoba
mohly
v libovolném pořadí vyskytovat elementy jméno
,
příjmení
a případně přezdívka
,
za kterými bude následovat e-mailová adresa.
r
n
g<element name="osoba"> <interleave> <element name="jméno"> <text/> </element> <element name="příjmení"> <text/> </element> <optional> <element name="přezdívka"> <text/> </element> </optional> </interleave> <element name="email"> <text/> </element> </element>
V kompaktní syntaxi se místo vzoru interleave
používá konektor
„&
“.
r
n
celement osoba {
(element jméno { text }
& element příjmení { text }
& element přezdívka { text }?),
element email { text }
}
Toto schéma pak umožňuje například zápis následujících dokumentů:
<osoba> <jméno>Jan</jméno> <příjmení>Novák</příjmení> <přezdívka>Mařena</přezdívka> <email>jan@example.com</email> </osoba> <osoba> <jméno>Jan</jméno> <přezdívka>Mařena</přezdívka> <příjmení>Novák</příjmení> <email>jan@example.com</email> </osoba> <osoba> <jméno>Jan</jméno> <příjmení>Novák</příjmení> <email>jan@example.com</email> </osoba> <osoba> <příjmení>Novák</příjmení> <jméno>Jan</jméno> <email>jan@example.com</email> </osoba> <osoba> <přezdívka>Mařena</přezdívka> <příjmení>Novák</příjmení> <jméno>Jan</jméno> <email>jan@example.com</email> </osoba>
Vzor interleave
je velmi
flexibilní a vysoce převyšuje podobné možnosti
v WXS nebo DTD. Není proto problém namodelovat dokument,
který umožní zadat titul před i za jméno a přitom nebude záležet
na pořadí jména a příjmení.
r
n
g<element name="osoba"> <optional> <element name="titul"> <text/> </element> </optional> <interleave> <element name="jméno"> <text/> </element> <element name="příjmení"> <text/> </element> </interleave> <optional> <element name="titul"> <text/> </element> </optional> </element>
r
n
celement osoba {
element titul { text }?,
(element jméno { text }
& element příjmení { text }),
element titul { text }?
}
Vzor interleave
toho však umí
mnohem více. Jak ostatně napovídá jeho název, umožňuje prolínání
elementů ve skupinách. Jednotlivé vzory uvnitř interleave
se tak mohou prolínat, ale pořadí
elementů v těchto vzorech zůstane zachováno. Pojďme si to ukázat
na příkladě. Dejme tomu, že si chceme v dokumentu XML uchovávat
informace o zákaznících:
<zákazník> <jméno>Pepa</jméno> <ulice>Nádražní 7</ulice> <město>Liberec</město> <psč>460 00</psč> <telefon>800121314</telefon> <email>pepa@example.com</email> </zákazník>
Mezi tyto elementy pak budeme chtít libovolným způsobem vkládat
poznámky jako element poznámka
. Například
takto:
<zákazník> <poznámka>Je bohatý, určitě ho přesvědčíme, ať si něco koupí</poznámka> <jméno>Pepa</jméno> <ulice>Nádražní 7</ulice> <město>Liberec</město> <psč>460 00</psč> <poznámka>To PSČ musíme ještě upřesnit</poznámka> <telefon>800121314</telefon> <email>pepa@example.com</email> <poznámka>Ta e-mailová adresa vypadá nějak divně</poznámka> </zákazník>
S využitím vzoru interleave
bude výsledné schéma velmi
jednoduché.
r
n
g<element name="zákazník"> <interleave> <group> <element name="jméno"> <text/> </element> <element name="ulice"> <text/> </element> <element name="město"> <text/> </element> <element name="psč"> <text/> </element> <element name="telefon"> <text/> </element> <element name="email"> <text/> </element> </group> <zeroOrMore> <element name="poznámka"> <text/> </element> </zeroOrMore> </interleave> </element>
r
n
celement zákazník {
((element jméno { text },
element ulice { text },
element město { text },
element psč { text },
element telefon { text },
element email { text })
& element poznámka { text }*)
}
Smíšený obsah je název pro obsah elementu, který může obsahovat jak text, tak další vnořené elementy. Tato struktura je obvyklá například pro odstavce. Ty většinou obsahují text, ale občas je tento text obalen v elementech, které textu přiřazují význam, mění formátování nebo třeba vkládají odkaz.
Například na následující ukázce má element
odstavec
smíšený obsah, protože kromě textu se
v něm podle potřeby mohou opakovat elementy pojem
a odkaz
.
<odstavec>Odstavce typicky obsahují <pojem>smíšený obsah</pojem>. Text se může střídat s <odkaz url="http://www.kosek.cz">odkazy</odkaz> a dalšími <pojem>elementy</pojem>.</odstavec> <odstavec>Odstavec může obsahovat i jen text.</odstavec> <odstavec><pojem>Nebo jen element.</pojem></odstavec>
V takovém případě stačí použít interleave
a pomocí něj dovolit prolínání
textu s libovolným počtem elementů pojem
a
odkaz
.
r
n
g<element name="odstavec"> <interleave> <zeroOrMore> <element name="pojem"> <text/> </element> </zeroOrMore> <zeroOrMore> <element name="odkaz"> <attribute name="url"/> <text/> </element> </zeroOrMore> <text/> </interleave> </element>
r
n
celement odstavec {
element pojem { text }*
& element odkaz { attribute url { text }, text }*
& text
}
U vzoru text
není potřeba
nastavovat opakování, protože tento vzor automaticky vyhovuje
libovolném počtu textových uzlů včetně nulového.
Protože je smíšený obsah v dokumentově orientovaných
schématech používán poměrně často, existuje pro něj v RELAX NG
zkrácený zápis. Místo interleave
můžeme použít vzor mixed
, ve kterém
se už neuvádí vzor pro text. Dostaneme tak o něco kratší a
přehlednější schéma.
r
n
g<element name="odstavec"> <mixed> <zeroOrMore> <element name="pojem"> <text/> </element> </zeroOrMore> <zeroOrMore> <element name="odkaz"> <attribute name="url"/> <text/> </element> </zeroOrMore> </mixed> </element>
Nicméně, když toto schéma vyzkoušíme, zjistíme, že vyžaduje, aby
se elementy pojem
, vyskytovaly před elementy
odkaz
. Toto zvláštní chování je dáno tím, že
specifikace RELAX NG říká, že pokud vzor mixed
obsahuje více jak jedno dítě jako svůj
obsah, jsou všechny děti obaleny vzorem pro skupinu group
. Naše schéma tak ve skutečnosti odpovídá
následujícímu zápisu.
r
n
g<element name="odstavec"> <mixed> <group> <zeroOrMore> <element name="pojem"> <text/> </element> </zeroOrMore> <zeroOrMore> <element name="odkaz"> <attribute name="url"/> <text/> </element> </zeroOrMore> </group> </mixed> </element>
A jak vidíme, práve seskupení vzorů má v případě klasického
smíšeného obsahu dost nepříjemné vedlejší efekty. Můžeme však ručně
group
nahradit za interleave
a dostaneme schéma, které se chová
tak, jak potřebujeme.
r
n
g<element name="odstavec"> <mixed> <interleave> <zeroOrMore> <element name="pojem"> <text/> </element> </zeroOrMore> <zeroOrMore> <element name="odkaz"> <attribute name="url"/> <text/> </element> </zeroOrMore> </interleave> </mixed> </element>
Tomuto zápisu odpovídá následující kompaktní syntaxe.
r
n
celement odstavec {
mixed {
element pojem { text }*
& element odkaz { attribute url { text }, text }*
}
}
RELAX NG sám o sobě nijak oslnivou podporu datových typů nenabízí. Nicméně nabízí mechanismus, jak jej používat s libovolnou externí knihovnou datových typů. Nejčastěji se přitom používají datové typy z WXS. Díky tomu můžeme i v RELAX NG kontrolovat, zda element nebo atribut obsahuje hodnotu vyhovující podmínkám nějakého datového typu.
Pro nastavení datového typu pro obsah elementu nebo atributu se
používá vzor data
. Jeho atribut
type
pak určuje datový
typ. Identifikátor použité knihovny typů se zadává v atributu
datatypeLibrary
.
Knihovna datových typů WXS je identifikována pomocí URI
http://www.w3.org/2001/XMLSchema-datatypes
.
r
n
g<element name="cena"> <data type="decimal" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"/> </element>
Zapisování použité knihovny typů u každého elementu
data
by bylo poměrně pracné. RELAX NG proto dědí
definici aktuální knihovny typů na všechny podelementy. V praxi se tak
knihovna nadefinuje jen jednou na kořenovém elementu schématu a platí
pro celé schéma.
r
n
g<element name="souřadnice" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <element name="x"> <data type="double"/> </element> <element name="y"> <data type="double"/> </element> </element>
V kompaktní syntaxi si můžeme pro knihovnu datových typů definovat prefix a ten pak používat při určení typu:
r
n
cdatatypes xs = "http://www.w3.org/2001/XMLSchema-datatypes"
element cena { xs:decimal }
Nicméně pro knihovnu datových typů WXS je implicitně
předdefinován prefix xsd
, takže jej deklarovat
nemusíme a můžeme jej rovnou použít:
r
n
celement cena { xsd:decimal }
U každého datového typu je možné určit parametry, které jej
dále upřesňují. Při použití datových typů WXS tak můžeme přímo
v RELAX NG nastavit většinu integritních omezení, která známe
z WXS. Pro nastavení parametrů se používá element param
s atributem name
.
Následující schéma demonstruje využití datových typů z WXS s nastavenými integritními omezeními. Jméno zaměstnance musí mít délku mezi 2 a 15 znaků, plat musí být menší než sto tisíc korun, ale vyšší než minimální mzda a nakonec rodné číslo se musí skládat z devíti nebo desíti číslic oddělených lomítkem.
r
n
g<element name="zaměstnanec" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <element name="jméno"> <data type="string"> <param name="minLength">2</param> <param name="maxLength">15</param> </data> </element> <element name="plat"> <data type="decimal"> <param name="minInclusive">6700</param> <param name="maxExclusive">100000</param> </data> </element> <element name="rč"> <data type="token"> <param name="pattern">\d{6}/\d{3,4}</param> </data> </element> </element>
r
n
celement zaměstnanec {
element jméno {
xsd:string { minLength = "2" maxLength = "15" }
},
element plat {
xsd:decimal { minInclusive = "6700" maxExclusive = "100000" }
},
element rč {
xsd:token { pattern = "\d{6}/\d{3,4}" }
}
}
Všimněte si, že pro rodné číslo používáme datový typ
token
. Jeho obsah se před validací normalizuje tak,
že se odříznou bílé znaky na jeho začátku a konci a opakovaný výskyt
bílých znaků za sebou uvnitř hodnoty se nahradí jednou
mezerou. Validací tak projdou i zápisy jako:
<rč> 123456/7890 </rč>
Kdybychom místo token
použili typ
string
, normalizace bílých znaků se nebude
provádět, a validací by prošly jen zápisy bez mezer:
<rč>123456/7890</rč>
Jako parametr můžeme použít všechna integritní omezení s výjimkou
enumeration
a whiteSpace
.
Použití integritního omezení enumeration
je
zakázáno, protože RELAX NG nabízí vlastní prostředky pro definování
seznamu hodnot přípustných pro nějaký atribut nebo element. Pro určení
přípustné hodnoty se používá vzor value
. Pomocí vzoru choice
můžeme více přípustných hodnot
zkombinovat do jednoho výčtu.
Následující schéma definuje element cena
,
který obsahuje desetinné číslo a atribut měna
. Přípustné hodnoty pro tento atribut
jsou definovány výčtem.
r
n
g<element name="cena" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <attribute name="měna"> <choice> <value>CZK</value> <value>USD</value> <value>EUR</value> </choice> </attribute> <data type="decimal"/> </element>
r
n
celement cena {
attribute měna { "CZK" | "USD" | "EUR" },
xsd:decimal
}
Zcela obdobně lze výčtový typ použít i pro určení obsahu elementu.
Před porovnáním hodnoty z dokumentu s hodnotami ve výčtu se
provede normalizace této hodnoty (stejně jako v případě datového typu
token
). Pomocí atributu type
můžeme určit i jiný typ. Pak se
použijí jeho pravidla pro normalizaci a kromě shody s hodnotou se bude
testovat i shoda s datovým typem. Nejčastěji se používá typ
string
, který nenormalizuje bílé znaky a zaručí, že
ve validním dokumentu se hodnota z výčtu vyskytla přesně, včetně
případných bílých znaků.
Každá hodnota ve výčtu přitom může mít určen svůj vlastní datový typ. U každé hodnoty se tak může provádět jiný způsob normalizace bílých znaků. Jde například vytvořit schéma, kterým projde dokument:
<cena měna=" CZK ">67.50</cena>
Ale neprojde dokument:
<cena měna=" USD ">67.50</cena>
Protože pro hodnotu USD
nastavíme typ
string
a pro hodnotu CZK
typ
token
.
r
n
g<element name="cena" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <attribute name="měna"> <choice> <value type="token">CZK</value> <value type="string">USD</value> <value>EUR</value> </choice> </attribute> <data type="decimal"/> </element>
r
n
celement cena {
attribute měna { token "CZK" | string "USD" | "EUR" },
xsd:decimal
}
Někdy se nám může více hodit určit povolené hodnoty negativně,
namísto pozitivně. Tj. místo výčtu povolených hodnot potřebujeme použít
výčet zakázaných hodnot. Toho můžeme dosáhnout pomocí vzoru
except
.
Můžeme pak snadno definovat, že v dokumentu nechceme mít osoby, které se prohlašují za fašisty.
r
n
g<element name="osoba"> <element name="jméno"> <text/> </element> <element name="politickéVyznání"> <data type="string"> <except> <value>fašista</value> </except> </data> </element> </element>
r
n
celement osoba {
element jméno { text },
element politickéVyznání { string - ("fašista") }
}
Zakázaných hodnot můžeme určit i více, pokud vzor except
zkombinujeme s výčtovým vzorem
choice
.
r
n
g<element name="osoba"> <element name="jméno"> <text/> </element> <element name="politickéVyznání"> <data type="string"> <except> <choice> <value>fašista</value> <value>komunista</value> <value>anarchista</value> </choice> </except> </data> </element> </element>
r
n
celement osoba {
element jméno { text },
element politickéVyznání {
string - (("fašista" | "komunista" | "anarchista"))
}
}
RELAX NG umožňuje definovat, že obsahem nějakého elementu nebo atributu je seznam složený z několika hodnot oddělených bílými znaky. Je tak možné kontrolovat strukturu, která není explicitně vyjádřená pomocí značkování. Z hlediska XML to sice není úplně nejlepší přístup, ale mnoho jazyků používá strukturovaný obsah elementů pro zkrácení zápisu.
To, že se někde může vyskytovat seznam hodnot, se zapisuje
pomocí vzoru list
. Jeho obsahem je
pak vzor, který definuje datové typy nebo hodnoty, které se mohou
v seznamu objevit.
Následující schéma tak ukazuje použití seznamu.
r
n
g<element name="osoba"> <element name="jméno"> <text/> </element> <element name="oblíbenéHudebníStyly"> <list> <oneOrMore> <data type="token"/> </oneOrMore> </list> </element> </element>
r
n
celement osoba {
element jméno { text },
element oblíbenéHudebníStyly { list { token+ } }
}
Můžeme pak vytvářet dokumenty jako:
<osoba> <jméno>Pepa</jméno> <oblíbenéHudebníStyly>jazz folk rock</oblíbenéHudebníStyly> </osoba>
Vzor pro seznam může samozřejmě používat další možnosti RELAX NG pro tvorbu složitějších vzorů, takže není problém určit výčtem přípustné hodnoty pro položky seznamu.
r
n
g<element name="osoba"> <element name="jméno"> <text/> </element> <element name="oblíbenéHudebníStyly"> <list> <oneOrMore> <choice> <value>jazz</value> <value>rock</value> <value>folk</value> <value>country</value> <value>blues</value> <value>ska</value> <value>klasika</value> <value>hiphop</value> <value>jungle</value> <value>drum'n'bass</value> </choice> </oneOrMore> </list> </element> </element>
r
n
celement osoba {
element jméno { text },
element oblíbenéHudebníStyly {
list { ("jazz" | "rock" | "folk" | "country" | "blues" | "ska"
| "klasika" | "hiphop" | "jungle" | "drum'n'bass" )+ }
}
}
Položky seznamu mohou mít dokonce různé datové typy. Například můžeme definovat element pro zaznamenání rozměru nábytku:
<skříňka rozměry="40 38.5 90 cm"/>
Atribut rozměry
je v tomto
případě rozumné definovat jako seznam, jehož první tři hodnoty jsou
číslo a čtvrtá je řetězec s jednou z předdefinovaných délkových
jednotek.
r
n
g<element name="skříňka"> <attribute name="rozměry"> <list> <data type="decimal"/> <data type="decimal"/> <data type="decimal"/> <choice> <value>cm</value> <value>mm</value> </choice> </list> </attribute> </element>
r
n
celement skříňka {
attribute rozměry {
list { xsd:decimal, xsd:decimal, xsd:decimal, ("cm" | "mm" ) }
}
}
RELAX NG nabízí dva zabudované datové typy
string
a token
, které můžeme
používat bez určení knihovny datových typů. Oba typy reprezentují
textový řetězec. Typ token
navíc před validací
provádí normalizaci bílých znaků.
Jsou situace, kdy chceme, aby obsah elementu závisel na nějaké jiné hodnotě v dokumentu – například na hodnotě nějakého atributu. Většina schémových jazyků se s tímto požadavkem neumí vyrovnat, ale pro RELAX NG to není žádný problém. Tím, že vzory lze téměř libovolně kombinovat a mohou obsahovat i výčet (i jednoprvkový) povolených hodnot pro element a atribut, můžeme podobný požadavek velice jednoduše a přirozeně vyjádřit ve schématu.
Dejme tomu, že budeme chtít zaznamenávat informace z nějaké seznamky. Jak to tak bývá, budou nás zajímat jiné údaje u dam a jiné u pánů. Schéma by proto mělo na základě pohlaví vyžadovat jiné elementy u muže a jiné u ženy:
<seznamka> <osoba pohlaví="muž"> <jméno>Pepa</jméno> <věk>29</věk> <okres>Bruntál</okres> <auto>false</auto> <chata>true</chata> <konto>14500</konto> </osoba> <osoba pohlaví="žena"> <jméno>Martina</jméno> <věk>27</věk> <okres>Kladno</okres> <míry>90 60 90</míry> <vlasy>blondýna</vlasy> <oči>modré</oči> </osoba> </seznamka>
Chceme přitom samozřejmě zaručit, že u muže nepůjde zadat jeho míry a naopak. Následující schéma ukazuje, jak můžeme naše požadavky zachytit formalizovaně v podobě schématu:
r
n
g<element name="seznamka" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <oneOrMore> <element name="osoba"> <element name="jméno"> <text/> </element> <element name="věk"> <data type="positiveInteger"/> </element> <element name="okres"> <text/> </element> <choice> <group> <attribute name="pohlaví"> <value>muž</value> </attribute> <element name="auto"> <data type="boolean"/> </element> <element name="chata"> <data type="boolean"/> </element> <element name="konto"> <data type="decimal"/> </element> </group> <group> <attribute name="pohlaví"> <value>žena</value> </attribute> <element name="míry"> <list> <data type="decimal"/> <data type="decimal"/> <data type="decimal"/> </list> </element> <element name="vlasy"> <choice> <value>blondýna</value> <value>bruneta</value> <value>zrzka</value> </choice> </element> <element name="oči"> <data type="string"/> </element> </group> </choice> </element> </oneOrMore> </element>
r
n
celement seznamka {
element osoba {
element jméno { text },
element věk { xsd:positiveInteger },
element okres { text },
( (attribute pohlaví { "muž" },
element auto { xsd:boolean },
element chata { xsd:boolean },
element konto { xsd:decimal })
|
(attribute pohlaví { "žena" },
element míry { list { xsd:decimal, xsd:decimal, xsd:decimal } },
element vlasy { ("blondýna" | "bruneta" | "zrzka") },
element oči { xsd:string })
)
}+
}
RELAX NG nabízí velmi silné možnosti pro ukládání schémat do více souborů a jejich vzájemné kombinování a předefinovávání. Podrobný popis těchto možností naleznete například v [14]. My se podíváme alespoň na základní možnost modularizace v rámci jednoho schématu.
V praxi se často setkáme s tím, že se na několika místech schématu opakuje stejný vzor. Abychom jej nemuseli opisovat, je možné si pro něj definovat jméno a to pak opakovaně používat místo vzoru.
Předpokládejme, že si chceme u osoby ukládat následující údaje:
<osoba> <jméno>Jan Novák</jméno> <narozen>29.5.1957</narozen> <trvaléBydliště> <ulice>Korunní 2</ulice> <město>Praha 2</město> <psč>120 00</psč> </trvaléBydliště> <korespondenčníAdresa> <ulice>W. Piecka 17</ulice> <město>Praha 2</město> <psč>120 00</psč> </korespondenčníAdresa> </osoba>
Vidíme, že obsah elementů trvaléBydliště
a
korespondenčníAdresa
je zcela shodný a že by bylo
zbytečné jejich definici duplikovat. Můžeme si proto pomocí pomocí
elementu define
definovat pojmenovaný
vzor a pak jej použít. Při použití definic musíme použít ještě element
start
, kterým určíme, na jakém elementu
validace začíná. Aby celé schéma i nadále vyhovovalo syntaxi XML
a mělo jeden kořenový element, obalíme jej elementem grammar
.
r
n
g<grammar xmlns="http://relaxng.org/ns/structure/1.0"> <start> <element name="osoba"> <element name="jméno"> <text/> </element> <element name="narozen"> <text/> </element> <element name="trvaléBydliště"> <ref name="adresa"/> </element> <element name="korespondenčníAdresa"> <ref name="adresa"/> </element> </element> </start> <define name="adresa"> <element name="ulice"> <text/> </element> <element name="město"> <text/> </element> <element name="psč"> <text/> </element> </define> </grammar>
r
n
cstart =
element osoba {
element jméno { text },
element narozen { text },
element trvaléBydliště { adresa },
element korespondenčníAdresa { adresa }
}
adresa =
element ulice { text },
element město { text },
element psč { text }
Pojmenované vzory nám umožňují zkrátit a zpřehlednit zápis i v dalších případech. Například můžeme výrazně zkrátit naše schéma, které u osoby definovalo výskyt dvou až pěti telefonů.
r
n
g<grammar xmlns="http://relaxng.org/ns/structure/1.0"> <start> <element name="osoba"> <element name="jméno"> <text/> </element> <ref name="telefon"/> <ref name="telefon"/> <optional> <ref name="telefon"/> </optional> <optional> <ref name="telefon"/> </optional> <optional> <ref name="telefon"/> </optional> </element> </start> <define name="telefon"> <element name="telefon"> <text/> </element> </define> </grammar>
r
n
cstart =
element osoba {
element jméno { text },
telefon,
telefon,
telefon?,
telefon?,
telefon?
}
telefon = element telefon { text }
Schémata uložená v několika souborech lze skládat pomocí
elementu include
. RELAX NG navíc
umožňuje velice jednoduše rozšiřovat existující vzory tím, že se k nim
přidají nové vzory pomocí vzoru choice
nebo interleave
. Kombinováním těchto
přístupů lze vytvářet velice flexibilní, modulární a snadno
modifikovatelná schémata. Ukažme si vše na příkladě. Dejme tomu, že
máme následující schéma definující jednoduchý adresář.
Příklad 4.1. Schéma jednoduchého adresáře –
rng/adresar.rng
r
n
g<?xml version="1.0" encoding="UTF-8"?> <grammar xmlns="http://relaxng.org/ns/structure/1.0"> <start> <ref name="adresář"/> </start> <define name="přezdívka"> <element name="přezdívka"> <text/> </element> </define> <define name="plnéJméno"> <element name="plnéJméno"> <element name="křestní"> <text/> </element> <element name="příjmení"> <text/> </element> </element> </define> <define name="jméno"> <choice> <ref name="přezdívka"/> <ref name="plnéJméno"/> </choice> </define> <define name="email"> <element name="email"> <text/> </element> </define> <define name="osoba"> <element name="osoba"> <ref name="jméno"/> <ref name="email"/> </element> </define> <define name="adresář"> <element name="adresář"> <oneOrMore> <ref name="osoba"/> </oneOrMore> </element> </define> </grammar>
Příklad 4.2. Schéma jednoduchého adresáře –
rng/adresar.rnc
r
n
cstart = adresář
přezdívka = element přezdívka { text }
plnéJméno =
element plnéJméno {
element křestní { text },
element příjmení { text }
}
jméno = přezdívka | plnéJméno
email = element email { text }
osoba = element osoba { jméno, email }
adresář = element adresář { osoba+ }
Nyní budeme chtít vytvořit nové schéma, které v místě, kde jsou
nyní dovoleny elementy plnéJméno
a přezdívka
, dovolí zadat i element
krycíJméno
. Všimněte si, že schéma je již dopředu
navrženo tak, aby jej šlo snadno rozšiřovat a proto existuje pro každý
element odpovídající pojmenovaný vzor – v případě jména to je
pojmenovaný vzor jméno
.
RELAX NG umožňuje při definici pojmenovaného vzoru říci, že se
má jeho obsah zkombinovat s již existujícím vzorem stejného
jména. Způsob kombinace se přitom určuje pomocí atribut combine
. Našeho cíle tak
dosáhneme velice snadno, stačí načíst již existující schéma a do vzoru
pro jméno jako další alternativu přidat
krycíJméno
.
Příklad 4.3. Skládání vzorů –
rng/adresar-rozsireni.rng
r
n
g<?xml version="1.0" encoding="UTF-8"?> <grammar xmlns="http://relaxng.org/ns/structure/1.0"> <include href="adresar.rng"/> <define name="krycíJméno"> <element name="krycíJméno"> <text/> </element> </define> <define name="jméno" combine="choice"> <ref name="krycíJméno"/> </define> </grammar>
V kompaktní syntaxi se combine
nahrazuje pomocí |=
a &=
.
Příklad 4.4. Skládání vzorů –
rng/adresar-rozsireni.rnc
r
n
cinclude "adresar.rnc"
krycíJméno = element krycíJméno { text }
jméno |= krycíJméno
Výše popsaný přístup se hodí v případech, kdy chceme existují
schéma rozšířit. Existují však situace, kdy jej chceme zúžit nebo
změnit. V tomto případě můžeme během načítání externího schématu
předefinovat libovolný pojmenovaný vzor. Stačí nové definice uvést
uvnitř elementu include
. Následující
příklad upraví stávající schéma adresáře tak, že jako kořenový element
se musí uvést element osoba
a bude se provádět
mnohem striktnější kontrola tvaru emailové adresy.
Příklad 4.5. Redefinice vzorů během načítání schématu –
rng/adresar-redefinice.rng
r
n
g<?xml version="1.0" encoding="UTF-8"?> <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <include href="adresar.rng"> <start> <ref name="osoba"/> </start> <define name="email"> <element name="email"> <data type="string"> <param name="pattern">[!-~-[()<>@;:\\"\[\]]]+@[!-~-[()<>@;:\\"\[\]]]+</param> </data> </element> </define> </include> </grammar>
Příklad 4.6. Redefinice vzorů během načítání schématu –
rng/adresar-redefinice.rnc
r
n
cinclude "adresar.rnc" {
start = osoba
email =
element email {
xsd:string {
pattern = '[!-~-[()<>@;:\\"\[\]]]+@[!-~-[()<>@;:\\"\[\]]]+'
}
}
}
RELAX NG samozřejmě umožňuje deklarovat elementy a atributy, které patří do nějakého jmenného prostoru. Všechny předchozí ukázky zatím jmenné prostory nepoužívaly a elementy a atributy tak nepatřily do žádného jmenného prostoru.
V deklaraci každého elementu a atributu můžeme použít
atribut ns
a do něj
zadat jmenný prostor, do kterého má element nebo atribut patřit. Takže
následujícímu schématu:
r
n
g<element xmlns="http://relaxng.org/ns/structure/1.0" name="a" ns="urn:x-kosek:schemas:pokus"> <element name="b" ns="urn:x-kosek:schemas:pokus"> <text/> </element> <element name="c" ns="urn:x-kosek:schemas:pokus"> <text/> </element> </element>
Vyhoví například dokumenty:
<a xmlns="urn:x-kosek:schemas:pokus"> <b>foo</b> <c>bar</c> </a> <p:a xmlns:p="urn:x-kosek:schemas:pokus"> <p:b>foo</p:b> <p:c>bar</p:c> </p:a>
Protože opakování atributu ns
u každé definice elementu by bylo
velmi pracné a vedlo by k chybám v případě, že na něj
zapomeneme, dědí se jmenný prostor z elementů, které jsou ve
schématu předky elementu. Toto však platí jen pro elementy, atributy
musíme vždy do jmenného prostoru přidat explicitně. Předchozí schéma
proto můžeme zkrátit jako:
<element xmlns="http://relaxng.org/ns/structure/1.0" name="a" ns="urn:x-kosek:schemas:pokus"> <element name="b"> <text/> </element> <element name="c"> <text/> </element> </element>
Definujeme-li dokument, který používá více jmenných prostorů,
můžeme si pro jmenné prostory nadeklarovat prefixy a ty pak používat
před jménem elementu a atributu. Zápis je tak opět jednodušší než
v případě použití atributu ns
.
Například následujícímu schématu:
r
n
g<element xmlns="http://relaxng.org/ns/structure/1.0" name="art:článek" xmlns:art="urn:x-kosek:schemas:clanek" xmlns:dc="http://purl.org/dc/elements/1.1/"> <element name="dc:title"> <text/> </element> </element>
které je ekvivalentní schématu:
r
n
g<element xmlns="http://relaxng.org/ns/structure/1.0" name="článek" ns="urn:x-kosek:schemas:clanek"> <element name="title" ns="http://purl.org/dc/elements/1.1/"> <text/> </element> </element>
vyhoví například následující dokumenty:
<článek xmlns="urn:x-kosek:schemas:clanek" xmlns:dc="http://purl.org/dc/elements/1.1/"> <dc:title>Ze života hmyzu</dc:title> </článek> <art:článek xmlns:art="urn:x-kosek:schemas:clanek" xmlns:dc="http://purl.org/dc/elements/1.1/"> <dc:title>Ze života hmyzu</dc:title> </art:článek> <článek xmlns="urn:x-kosek:schemas:clanek"> <title xmlns="http://purl.org/dc/elements/1.1/">Ze života hmyzu</title> </článek>
V kompaktní syntaxi se prefix jmenného prostoru definuje pomocí
klíčového slova namespace
. Poslední schéma tak
můžeme v kompaktní syntaxi zapsat jako:
r
n
cnamespace art = "urn:x-kosek:schemas:clanek"
namespace dc = "http://purl.org/dc/elements/1.1/"
element art:článek {
element dc:title { text }
}
Jeden jmenný prostor můžeme definovat jako implicitní. Elementy, které pak v názvu nemají prefix, do tohoto jmenného prostoru budou patřit. Předchozí schéma proto můžeme zapsat i jako:
r
n
cdefault namespace = "urn:x-kosek:schemas:clanek"
namespace dc = "http://purl.org/dc/elements/1.1/"
element článek {
element dc:title { text }
}
Případně jako:
r
n
cnamespace art = "urn:x-kosek:schemas:clanek"
default namespace = "http://purl.org/dc/elements/1.1/"
element art:článek {
element title { text }
}
Implicitní jmenný prostor je však vhodný zejména pro schémata, kde je většina elementů v jednom jmenném prostoru.
r
n
cdefault namespace = "urn:x-kosek:schemas:pokus"
element a {
element b { text },
element c { text }
}
RELAX NG umožňuje k libovolnému elementu schématu přidat atributy patřící do libovolného jmenného prostoru a skoro na každé místo ve schématu můžeme vložit element v jakémkoliv jiném jmenném prostoru než používá RELAX NG. To můžeme využít pro zápis dokumentace. Pomocí XSLT pak můžeme poměrně snadno generovat dokumentaci třeba v podobě hypertextově provázané sady HTML stránek.
Příklad 4.7. Dokumentace RNG schématu zapisovaná v XHTML –
rng/dokumentace-xhtml.rng
r
n
g<?xml version="1.0" encoding="UTF-8"?> <element name="osoba" xmlns="http://relaxng.org/ns/structure/1.0" xmlns:html="http://www.w3.org/1999/xhtml"> <optional> <html:p>Přehled titulů úvaděných před jménem. Jejich popis najdete <html:a href="http://www.stuba.sk/svk1/vztahy_s_ver/spektrum/2003/april2003/tituly.html">na stránce SAV</html:a>.</html:p> <element name="titul"> <text/> </element> </optional> <interleave> <element name="jméno"> <text/> </element> <element name="příjmení"> <text/> </element> </interleave> <optional> <html:p>Titul za jménem</html:p> <element name="titul"> <text/> </element> </optional> </element>
Protože kompaktní syntaxe není založená na XML, musí se dokumentace vkládaná v XML převést do speciální notace, kde se hranaté závorky používají pro simulaci elementů.
Příklad 4.8. Dokumentace schématu zapsaná v kompaktní syntaxi –
rng/dokumentace-xhtml.rnc
r
n
cnamespace html = "http://www.w3.org/1999/xhtml"
element osoba {
[
html:p [
"Přehled titulů úvaděných před jménem. Jejich popis najdete \x{a}"
html:a [
href =
"http://www.stuba.sk/svk1/vztahy_s_ver/spektrum/2003/april2003/tituly.html"
"na stránce SAV"
]
"."
]
]
(element titul { text }?),
(element jméno { text }
& element příjmení { text }),
[ html:p [ "Titul za jménem" ] ] (element titul { text }?)
}
Vystačíme-li si pro dokumentaci pouze s textovými komentáři, můžeme používat RELAX NG anotace. Zapisují se ve vlastním jmenném prostoru.
Příklad 4.9. Dokumentace RNG schématu
r
n
g<?xml version="1.0" encoding="UTF-8"?> <element name="osoba" xmlns="http://relaxng.org/ns/structure/1.0" xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0"> <optional> <a:documentation>Titul před jménem</a:documentation> <element name="titul"> <text/> </element> </optional> <interleave> <element name="jméno"> <text/> </element> <element name="příjmení"> <text/> </element> </interleave> <optional> <a:documentation>Titul za jménem</a:documentation> <element name="titul"> <text/> </element> </optional> </element>
Výhodou tohoto přístupu je, že kompaktní syntaxe nabízí
jednoduchou syntaxi pro zápis takové dokumentace. Začíná-li text na
řádce dvojicí znaků „##
“, považuje se
za komentář, který je součástí dokumentace.
Příklad 4.10. Dokumentace v RNC schématu
r
n
celement osoba {
## Titul před jménem
(element titul { text }?),
(element jméno { text }
& element příjmení { text }),
## Titul za jménem
(element titul { text }?)
}