V následující části se podíváme na některá pravidla získaná praktickým používáním schémat. Tato pravidla nemusí platit ve všech případech, ale ve většině případů se vám rozhodně vyplatí se jimi řídit.
Ve všech případech je možné atribut nahradit vnořeným podelementem. Mohlo by se proto zdát, že atributy jsou v XML zcela zbytečné. Nicméně existují dva případy, kdy se jejich použití může hodit:
Potřeba kompaktního zápisu – hodnota atributu je uzavřená v uvozovkách nebo apostrofech, není potřeba ji uzavírat koncovým tagem. Ve většině případů je tak zapsání atributu podstatně kratší. To může mít význam při návrhu schémat pro dokumenty, které se budou editovat především ručně bez použití nějakých speciálních XML editorů. Na druhou stranu je pravda, že bychom se při návrhu schématu neměli nechat příliš omezovat požadavky kladenými nějakou nedostatečnou aplikací. Aplikace se mění a data v XML zůstávají – návrh dobrého formátu by proto měl mít přednost.
Zjednodušení modelu obsahu – atributy se ve schémových jazycích jako WXS nebo DTD definují odděleně od podelementů. V některých případech by proto přesunutí atributu do podelementu mohlo vést k nutnosti rozvolnit stávající model obsahu a výsledkem by bylo schéma, které by bylo volnější než jsme původně zamýšleli.
Jaká existují další pravidla? U jednoho elementu není možné mít dva atributy stejného jména. Z tohoto důvodu nejde do atributu ukládat hodnoty s opakovaným výskytem.
Hodnotu atributu také nejde dále strukturovat pomocí podelementů. Atributy se proto nehodí pro uchovávání hodnot, které je potřeba dále strukturovat nebo lze očekávat, že v budoucnosti potřeba dalšího strukturování vznikne. Potřeba dalšího strukturování však hrozí u všech informací, které mohou obsahovat volný text. Nikdy nevíme, kdy náš formát dat začnou používat třeba v Japonsku nebo v Izraeli. Do japonského textu se však poměrně často vkládají tzv. Ruby anotace, které slouží k zápisu alternativy nějakého textu v jednodušší slabikové abecedě nebo v latince. Podobně, při kombinaci anglického textu s hebrejským je potřeba pomocí elementu označit, který text je anglicky a který hebrejský, aby se při zobrazování mohl správně změnit směr sazby textu.
Například v japonštině se „Tokyo“ v písmu kanji zapíše jako „東京“. U méně obvyklých slov se však nad kanji zápis často zapisuje i výslovnost pomocí slabikové abecedy hiragana:
text anotace Ruby → | とう | きょう | |
základní text → | 東 | 京 |
Je jasné, že text s anotací nejde reprezentovat prostým řetězcem, ale je k tomu potřeba struktura elementů. Naše ukázka by se pomocí značkování Ruby zapsala jako:
<ruby> <rb>東</rb> <rt>とう</rt> <rb>京</rb> <rt>きょう</rt> </ruby>
Docházíme tedy k závěru, že do atributů je vhodné ukládat pouze hodnoty, u kterých dopředu známe obor hodnot a tento obor je poměrně omezený. Do této kategorie spadají například čísla, data nebo textové hodnoty, pro které máme číselník (např. kódy měn apod.).
Každý nově navržený XML formát by měl definovat elementy ve vlastním jmenném prostoru. Elementy, které nepatří do jmenného prostoru nejde snadno a jednoznačně kombinovat v jednom dokumentu s jinými elementy. Uzavíráme si tak do budoucna cestu pro využití našeho formátu způsoby, které si dnes ještě ani nedovedeme představit.
Do jmenného prostoru by měly patřit všechny elementy, jejich
atributy bychom přitom do jmenného prostoru zařazovat neměli. To
znamená, že v WXS použijeme atribut targetNamespace
a atribut elementFormDefault
nastavíme na hodnotu
qualified
(viz 3.5 – „Jmenné prostory“). V RELAX NG se přiřazení jmenného prostoru
provádí atributem ns
(viz 4.5 – „Jmenné prostory“).
Otázkou zůstává, jak správně zvolit název jmenného prostoru pro nově vytvářené schéma. Vhodné je, aby byl název intuitivní, snadno zapamatovatelný a navržený tak, aby vás neomezil do budoucna. Název jmenného prostoru musí mít tvar URI adresy a dnes se běžně používají jak URN tak URL. Nejde jednoznačně říci, která z těchto variant je lepší.
Při používání URN musíme použít buď experimentální prostor
začínající písmenem x
nebo jej odvodit
z doménového jména. Například já, jako vlastník domény kosek.cz,
bych mohl používat URN začínající na:
urn:x-traktor:… urn:x-test:… urn:cz-kosek:…
Další část URN by měla naznačit, že URI se používá jako
identifikátor jmenného prostoru (použitím slova jako je
ns
nebo namespace
) a
identifikovat jméno schématu. Následuje ukázka několika existujících
i smyšlených jmenných prostorů, která využívají URN:
urn:oasis:names:tc:entity:xmlns:xml:catalog urn:oasis:names:specification:ubl:schema:xsd:DocumentStatusCode-1.0 urn:x-test:ns:faktura urn:x-test:namespace:faktura urn:cz-kosek:ns:kalendar
Stále častější bývá používání URL jako názvů jmenných prostorů. Jejich výhoda spočívá v tom, že na jejich adresu lze umístit dokumentaci schématu a odkazy na související dokumenty. Nevýhodu lze zase spatřovat v tom, že začínající uživatelé XML jsou poněkud zmateni tím, že název jmenného prostoru je jen identifikátor a že se při zpracování dokumentu nečtou žádná data z URL adresy odpovídající názvu jmenného prostoru.
Rozhodneme-li se používat pro názvy jmenných prostorů URL,
musíme je obzvláště pečlivě navrhnout, aby nekolidovaly
s adresami používanými pro dokumenty umístěnými na webovém serveru.
Obvykle se to řeší tak, že hned první část cesty v URL obsahuje
slovo ns
nebo namespace
a tyto
URL adresy jsou vyhrazeny pro tvorbu jmenných prostorů:
http://docbook.org/ns/docbook http://relaxng.org/ns/structure/1.0 http://obix.com/ns/module/version http://kosek.cz/namespace/kalendar
Někdy může být užitečné do URL zabudovat i číslo roku, aby se v budoucnu dal prostor URL rozšiřovat. Tento přístup využívají například jmenné prostory W3C:
http://www.w3.org/1999/xhtml http://www.w3.org/1999/XSL/Transform http://www.w3.org/2001/XMLSchema
Na adresu jmenného prostoru pak bývá vhodné umístit HTML stránku (nebo ještě lépe dokument RDDL), která stručně popíše jmenný prostor, odkáže na dokumentaci jeho elementů a případně i na odpovídající schéma, existuje-li. Dokument bychom měli vystavit už z toho důvodu, že většina méně znalých se bude snažit psát adresu jmenného prostoru do prohlížeče, protože bude vypadat jako obyčejné URL.
Volbě názvu elementů a atributů je dobré věnovat zvýšenou pozornost, protože přispějí ke srozumitelnosti a použitelnosti schématu. Rozhodně není vhodné používat nesrozumitelné a kryptické názvy elementů jako A01, A02, … A72, byť by se třeba takto jednotlivé pole jmenovaly v nějakém starším formátu, ze kterého se přechází na XML. Ve starších formátech je toto pojmenování většinou dáno technickými omezení doby a zvolené technologie pro ukládání dat. Potřebujeme-li z důvodů zpětné kompatibility zachovat původní jména, můžeme je uložit do atributů s fixní hodnotou ve schématu nebo si mapování uložit v nějaké externí mapovací tabulce (která samozřejmě může mít podobu dokumentu XML, aby šla snadno použít např. při zpracování dokumentů pomocí XSLT).
Na druhou stranu bychom se samozřejmě měli vyvarovat
i opačných extrémů, jako je element s názvem
SPZneboRegistračníZnačkaMotorovéhoVozidla
.
Název by měl být samopopisný v jeho kontextu, ale neměl by
být na druhou stranu příliš dlouhý. U víceslovných názvů je dobré
jednotlivá slova oddělit např. změnou velikosti písma, nebo vložením
pomlčky či podtržítka. Např.: JednotkováCena
,
jednotkováCena
nebo
jednotková_cena
. Důležité je rozhodnout se pro
jednu konvenci a tu pak konzistentně používat. V opačném případě
budou autoři vytvářející dokumenty podle vašeho schématu
zmatení.
Většina schémových jazyků umožňuje pro atributy (a někdy i pro elementy) určit implicitní hodnotu, která se atributu/elementu přiřadí, není-li atribut/element v dokumentu uveden. Používání této vlastnosti se v poslední době nedoporučuje, protože dokument pak obsahuje jiné informace, když je zpracován se schématem, a bez schématu.
Ve většině případů není schéma statický dokument, který jednou vznikne a už se dále nemění. Budoucnost obvykle přináší nové požadavky, pro které je nutné schéma upravit. Dnes se nejčastěji používá následující přístup.
Verze schématu se uvádí v atributu version
u kořenového elementu
dokumentu. S každým novou verzí schématu se toto číslo zvyšuje.
Dojde-li pak ve schématu k radikální změně – změna názvu
elementů, změna struktury dokumentu – obvykle nová verze
schématu používá jiný jmenný prostor, než ta předchozí. Je-li však
změna zpětně kompatibilní – přidají se například jen nové
nepovinné elementy – jmenný prostor se nemění. To umožňuje beze
změny používat i starší aplikace na nové dokumenty.
Počítáme-li s tím, že se schéma bude dále vyvíjet, nebo že má smysl, aby se dokumentu vkládaly i jiné elementy než definované ve schématu, je dobré je navrhnout jako otevřené. To znamená, že k libovolnému elementu dovoluje schéma přidat další podelementy.
Ve WXS se pro tuto definici používá element
any
. Jde u něj určit z jakého jmenného
prostoru jsou elementy povoleny a kolik jich může být. Nejvolnější
varianta je
<xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded"/>
která říká, že v daném místě se může vyskytovat libovolný
počet elementů z libovolného jmenného prostoru. Kromě
##any
můžeme použít ještě identifikátory
##targetNamespace
pro aktuální cílový jmenný
prostor, ##other
pro jakýkoliv jmenný prostor kromě
cílového a pak jde samozřejmě zadat URI adresu nějakého konkrétního
jmenného prostoru.
Pomocí atributu processContents
ještě můžeme určit, jak se
mají elementy popsané pomocí any
validovat. Hodnota
skip
říká, že se elementy nebudou validovat,
hodnota strict
říká, že se musí validovat a konečně
hodnota lax
říká, že se validace provede
v případě, že se pro elementy najde odpovídající schéma.
Vložení any
alespoň na některá místa schématu
podporuje rozšiřitelnost a je velmi žádoucí. Je však potřeba dávat
pozor na to, aby před elementy definovanými pomocí
any
nebyly volitelné elementy
(minOccurs="0"
), protože pak schéma není
jednoznačné. Například následující schéma tutu podmínku porušuje
a není proto korektní:
w
x
s<xs:element name="osoba"> <xs:complexType> <xs:sequence> <xs:element name="jmeno" type="xs:string"/> <xs:element name="email" type="xs:string" minOccurs="0"/> <xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element>
Problém je v tom, že při validaci dokumentu:
<osoba> <jmeno>Pepa</jmeno> <email>pepa@example.com</email> </osoba>
nejde určit, zda se element email
má
validovat podle element
nebo any
. WXS je však navržené tak, aby vždy šlo
instanci dokumentu jednoznačně mapovat na datové typy ve schématu – to
je nesmírně důležité například při data-bindingu.
Podobně rozšiřitelně a navíc s mnohem méně omezeními lze schémata navrhovat v RELAX NG. Musíme si nejprve definovat vzor pro jakýkoliv i opakující se element a ten pak použít na odpovídajícím místě schématu.
r
n
g<define name="anything"> <zeroOrMore> <choice> <element> <anyName/> <ref name="anything"/> </element> <attribute> <anyName/> <text/> </attribute> </choice> </zeroOrMore> </define>
Je zde použita speciální notace pro zápis jména elementu nebo
atributu. Vzor anyName
vyhoví jakémukoliv názvu.
Jde jej kombinovat i se vzorem except
a přesně
určit jaké jmenné prostory jsou povolené a zakázané.