Potřebujete pomoci s XML schématy?
Nabízím školení, konzultace, vývoj schémat na zakázku. Nevájte a kontaktujte mne.

Podpořte provoz stránek
Platba probíhá pomocí služby PayPal a je možné platit kartou nebo převodem z vašeho PayPal účtu.

Kapitola 4. Relax NG

4.1. Základní vzory
4.1.1. Textový obsah – text
4.1.2. Atribut – attribute
4.1.3. Element – element
4.1.4. Volitelný vzor – optional
4.1.5. Opakovaný vzor – oneOrMore
4.1.6. Libovolný počet opakování vzoru – zeroOrMore
4.1.7. Přesné určení počtu opakování vzoru
4.2. Pokročilé vzory
4.2.1. Seskupování vzorů – group
4.2.2. Výběr vzoru – choice
4.2.3. Prolínání vzorů – interleave
4.2.4. Smíšený obsah – mixed
4.2.5. Prázdný element – empty
4.3. Datové typy
4.3.1. Určení datového typu – data
4.3.2. Parametry datových typů – param
4.3.3. Výčtové typy
4.3.4. Vyloučené hodnoty – except
4.3.5. Seznamy – list
4.3.6. Zabudované typy
4.3.7. Kontextové modelování obsahu
4.4. Modularizace schématu
4.4.1. Pojmenované vzory
4.4.2. Skládání schémat
4.5. Jmenné prostory
4.6. Dokumentování schématu

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
c
element 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é.

4.1 Základní vzory

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í.

4.1.1 Textový obsah – text

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
c
text

4.1.2 Atribut – attribute

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
c
attribute měna { text }

4.1.3 Element – element

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
c
element 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
c
element 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
c
element 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
c
element osoba { element jméno { text }, element příjmení { text }, element email { text }, attribute narozen { text } }

4.1.4 Volitelný vzor – optional

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
c
element 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
c
element 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>

4.1.5 Opakovaný vzor – oneOrMore

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
c
element osoba { element jméno { text }, element příjmení { text }, element email { text }+, attribute narozen { text } }

4.1.6 Libovolný počet opakování vzoru – zeroOrMore

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
c
element 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>

4.1.7 Přesné určení počtu opakování vzoru

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.

Tabulka 4.1. Určení počtu opakování vzoru

Počet opakováníRNGRNC
1
0 nebo 1optional?
1 a víceoneOrMore +
0, 1 nebo vícezeroOrMore *

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
c
element 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.

4.2 Pokročilé vzory

4.2.1 Seskupování vzorů – group

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.

4.2.2 Výběr vzoru – 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
c
element 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
c
element 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>

4.2.3 Prolínání vzorů – interleave

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
c
element 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
c
element 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
c
element 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 }*) }

4.2.4 Smíšený obsah – mixed

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
c
element 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
c
element odstavec { mixed { element pojem { text }* & element odkaz { attribute url { text }, text }* } }

4.2.5 Prázdný element – empty

Pokud chceme definovat element, který je prázdný, musíme použít vzor empty.

r
n
g
<element name="br"> <empty/> </element>
r
n
c
element br { empty }

Obsahuje-li element i nějaké atributy, nemusíme vzor empty používat.

4.3 Datové typy

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.

4.3.1 Určení datového typu – data

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
c
datatypes 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
c
element cena { xsd:decimal }

4.3.2 Parametry datových typů – param

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
c
element 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.

4.3.3 Výčtové typy

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
c
element 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
c
element cena { attribute měna { token "CZK" | string "USD" | "EUR" }, xsd:decimal }

4.3.4 Vyloučené hodnoty – except

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
c
element 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
c
element osoba { element jméno { text }, element politickéVyznání { string - (("fašista" | "komunista" | "anarchista")) } }

4.3.5 Seznamy – list

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
c
element 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
c
element 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
c
element skříňka { attribute rozměry { list { xsd:decimal, xsd:decimal, xsd:decimal, ("cm" | "mm" ) } } }

4.3.6 Zabudované typy

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ů.

4.3.7 Kontextové modelování obsahu

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
c
element 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 }) ) }+ }

4.4 Modularizace schématu

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.

4.4.1 Pojmenované vzory

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
c
start = 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
c
start = element osoba { element jméno { text }, telefon, telefon, telefon?, telefon?, telefon? } telefon = element telefon { text }

4.4.2 Skládání schémat

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
c
start = 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
c
include "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">[&#33;-&#126;-[()&lt;>@;:\\&quot;\[\]]]+@[&#33;-&#126;-[()&lt;>@;:\\&quot;\[\]]]+</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
c
include "adresar.rnc" { start = osoba email = element email { xsd:string { pattern = '[!-~-[()<>@;:\\"\[\]]]+@[!-~-[()<>@;:\\"\[\]]]+' } } }

4.5 Jmenné prostory

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
c
namespace 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
c
default 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
c
namespace 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
c
default namespace = "urn:x-kosek:schemas:pokus" element a { element b { text }, element c { text } }

4.6 Dokumentování schématu

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
c
namespace 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
c
element osoba { ## Titul před jménem (element titul { text }?), (element jméno { text } & element příjmení { text }), ## Titul za jménem (element titul { text }?) }

© Jiří Kosek 2014

Tento dokument je určen výhradně pro osobní potřebu seznámení se schémovými jazyky. Jakékoliv jiné použití, včetně dalšího šíření, pořizování kopií, použití při školeních a výuce apod. je výslovně zakázáno a bude považováno za porušení autorských práv.

Dokument je zkrácenou verzí školicích materiálů používaných během školení XML schémata. Školení se mj. věnuje i problematice data-bindingu a využití informací ze schématu uvnitř aplikací.


Copyright © 2003-2013 Jiří Kosek