Jiří Kosek ml.
V úvodním článku o XML jsme si řekli, že XML-dokument může vyhovovat určitému typu dokumentu. Definice typu dokumentu (DTD) přitom říká, které elementy a atributy můžeme v dokumentu použít. Navíc je zde definováno, v jakých vzájemných vztazích mohou být jednotlivé elementy použity. DTD je tedy užitečný nástroj, který nám umožní hlídat, zda mají naše dokumenty správnou strukturu. Ve světě se používá mnoho DTD, které vyhovují různým požadavkům. Mezi jedno z nejznámějších patří například DocBook, které definuje elementy a atributy vhodné pro značkování technické dokumentace.
Tím, že naše dokumenty založíme na určitému DTD, získáme hned dvě výhody. Jednak můžeme pomocí parseru kontrolovat, zda má náš dokument správnou strukturu. Druhá výhoda je patrná při použití standardních DTD jako HTML nebo DocBook -- k dispozici budeme mít mnoho užitečných a jednoúčelových nástrojů navrhnutých pro konkrétní DTD. Například není problém pro DocBook sehnat definici stylů vhodných pro formátování dokumentace či programy, které umí dokumenty DocBook konvertovat do HTML a dalších formátů.
DTD se k dokumentu přidává pomocí deklarace typu dokumentu (DOCTYPE), která je umístěna na začátku dokumentu ihned za XML deklarací. Nejčastěji je DTD uloženo v samostatném souboru, aby mohlo být využíváno v mnoha dokumentech. V tomto případě má deklarace tvar:
<!DOCTYPE kořenový_element SYSTEM "URL">
URL přitom udává adresu nebo jméno souboru, ve kterém je uloženo DTD. Kořenový element je jméno elementu, který je v DTD definovaný jako kořenový -- tj. obsahuje všechny další elementy dokumentu.
Pro některá běžně používaná a standardizovaná DTD je zbytečné, aby
si parser a další aplikace četly DTD vždy ze sítě. Mnohem logičtější
by bylo, aby v systému byla přítomna lokální kopie souborů
s DTD. To je v XML možné pomocí takzvaných veřejných identifikátorů. K označení DTD
použijeme nějaký textový řetězec. XML-aplikace pak ve svém
konfiguračním souboru zjistí, ve kterém souboru je uloženo příslušné
DTD. Místo slova SYSTEM
nyní použijeme výraz
PUBLIC
, ze kterým uvedeme identifikátor DTD. Nakonec však
stejně musíme připojit URL, které ukazuje na soubor s DTD, aby
mohla aplikace DTD získat i v případě, že nerozpozná veřejný
identifikátor. Deklarace typu dokumentu pak může dopadnout třeba
takto:
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" "docbook.dtd">
DTD můžeme umístit i přímo do dokumentu pomocí následujícího zápisu.
<!DOCTYPE kniha [ ... DTD ... ]>
Umístění DTD přímo do dokumentu není příliš časté, protože pak ztrácíme možnost sdílení jednoho DTD mezi několika dokumenty. Užitečnější je však možnost zkombinovat obě předešlé metody a externí DTD upravit pomocí lokálně uvedených definic. Lokální část DTD se zpracovává ještě před tou externí a může tedy změnit některé definice uložené v externím DTD.
<!DOCTYPE kniha SYSTEM "kniha.dtd" [ ... definice, které změní nebo rozšíří kniha.dtd ... ]>
Když víme, jak připojit DTD k dokumentu, můžeme se podívat na to, jak samotné DTD vypadá. DTD obsahuje deklarace čtyř typů:
Deklarace nového elementu je velice jednoduchá. Má následující tvar:
<!ELEMENT název_elementu obsah_elementu>
Název elementu musí začínat písmenem. Další znaky názvu mohou
obsahovat písmena, číslice a některé speciální znaky jako
'.
', '-
', '_
' a
':
'. Délka jména není nikterak omezená. Narozdíl od HTML
je důležitá velikost písmen. Následující dva řádky deklarují dva různé
elementy kapitola
a Kapitola
.
<!ELEMENT kapitola ...> <!ELEMENT Kapitola ...>
Nejzajímavější je však poslední část deklarace elementu, která
definuje, co může element obsahovat. Nejjednodušší je prázdný element,
který nemůže obsahovat žádné další elementy nebo text. Příkladem
takového elementu mohou být například elementy br
a
hr
, které důvěrně známe z HTML. Jejich deklarace by
vypadala následovně:
<!ELEMENT br EMPTY> <!ELEMENT hr EMPTY>
Právě klíčové slovo EMPTY
určuje, že element nesmí nic
obsahovat. V dokumentu pak musíme psát buď
<br></br>
, nebo zkráceně
<br/>
. Není však možný zápis
<br>
, protože by parser zcela marně hledal
ukončovací tag </br>
.
Kromě výše zmíněných případů se prázdné elementy používají například pro vkládání obrázků. Pomocí atributů elementu pak určíme soubor, ve kterém je obrázek uložen.
Protipólem k EMPTY
je ANY
. Toto klíčové
slovo nám zajistí, že element může obsahovat libovolné další elementy
a text. ANY
se v praxi moc často nevyužívá, protože pro
potřeby většiny aplikací příliš uvolňuje strukturu dokumentu. Využití
nalezne například při návrhu a ladění DTD, kdy nechceme najednou
napsat celé DTD.
<!ELEMENT cokoliv ANY>
Většinou máme na vnořené elementy mnohem striktnější požadavky a s
EMPTY
a ANY
nevystačíme. V tomto případě pak
použijeme tzv. modelovou skupinu (model group). Modelová
skupina se používá pro definici elementů, které obsahují další
elementy nebo mají smíšený obsah (obsahují již přímo text a
elementy).
Modelová skupina je vždy uzavřena do kulatých závorek a obsahuje
alespoň jedno slovo. Tímto slovem nejčastěji bývá jméno elementu,
který může být obsažen v právě definovaném elementu. Vnořené
elementy můžeme navzájem kombinovat pomocí oddělovačů ',
'
a '|
'. Elementy oddělené čárkou musí následovat
v pořadí, v jakém jsou uvedeny. Pokud má tedy element
html
obsahovat záhlaví (head
) a tělo
(body
), použijeme deklaraci:
<!ELEMENT html (head, body)>
Pokud naopak elementy oddělíme znakem '|
' může být
obsažen pouze jeden z nich. Příklad: potomek může být dcera nebo
syn. V DTD to vyjádříme takto:
<!ELEMENT potomek (dcera | syn)>
Pomocí závorek můžeme obě dvě varianty navzájem kombinovat. Pokud
má nějaký element obsahovat elementy a
, b
a
za nimi buď c
nebo d
, použijeme modelovou
skupinu (a, b, (c | d))
.
Kromě pořadí elementů musíme určit jejich počet, zda jsou povinné
či zda se mohou opakovat. Pokud v modelové skupině uvedeme pouze jméno
elementu, musí být element přítomen právě jednou. Pokud je však výskyt
elementu nepovinný, uvedeme za jeho jméno znak '?
'. Pokud
například článek obsahuje vždy název, ale autora obsahovat nemusí,
můžeme použít následující deklaraci:
<!ELEMENT clanek (nazev, autor?)>
Další obvyklou situací je, že nějaký element se může opakovat, ale musí být přítomen alespoň jednou. Například kniha se skládá z několika kapitol, ale musí obsahovat alespoň jednu kapitolu:
<!ELEMENT kniha (kapitola+)>
Vraťme se k předchozímu příkladu a předkládejme, že článek může mít
více autorů a nemusí mít autora žádného. V tomto případě s výhodou
využijeme znak '*
', který indikuje libovolný počet
opakování.
<!ELEMENT clanek (nazev, autor*)>
Vše můžeme podle potřeby kombinovat. Pokud chceme vyjádřit, že
seznam obsahuje alespoň dvě položky, můžeme použít modelovou skupinu
(polozka, polozka+)
.
Indikátor počtu výskytů můžeme připojit i za modelovou
skupinu. Například zápis (a, b)?
říká, že se elementy
a
a b
buď musí vyskytovat v daném pořadí,
nebo nesmí být použity.
Speciální pozornost si zaslouží případ, kdy je obsahem elementu již
samotný text. To vyjádříme pomocí slova #PCDATA
. Pokud by
například element em
obsahoval již pouze text, a ne další
elementy, použili bychom pro jeho deklaraci zápis:
<!ELEMENT em (#PCDATA)>
Pokud může element obsahovat jak text tak elementy říkáme, že má
smíšený obsah. V tomto případě musí mít deklarace jeho obsahu
speciální tvar. #PCDATA
musí být uvedeno ve skupině jako
první, skupina musí být spojena pomocí operátoru '|
' a
musí být volitelně opakovatelná (*
). Například
<!ELEMENT em (#PCDATA, sub, sup)*> <!ELEMENT sub (#PCDATA)> <!ELEMENT sup (#PCDATA)>
Dokument pak může obsahovat následující text vyhovující DTD:
<em>Pozor na líh - C<sub>2</sub>H<sub>5</sub>OH.</em>
Máme za sebou úvod do tvorby té části DTD, která definuje použitelné elementy. Příště se podíváme na to, jak k elementům přidat atributy. Poté si již ukážeme, jak můžeme pomocí parseru kontrolovat správnost našich dokumentů.
Použití veřejných identifikátorů má mnohé výhody. Aby jsme je mohli
použít, musíme mít na svém počítači lokální kopie všech souborů DTD,
které používáme. V souboru catalog
pak musíme mít
k dispozici mapování mezi veřejnými identifikátory a
soubory. Máme-li například DTD uložena v adresáři
c:\dtd
, budeme mít pro DocBook v katalogovém souboru
řádek
PUBLIC "-//OASIS//DTD DocBook V3.1//EN" "c:\dtd\docbook.dtd"
Aby všechny aplikace katalogový soubor našly, musíme jeho umístění
uložit do proměnné prostředí SGML_CATALOG_FILES
.
Samotný význam jednotlivých části veřejného identifikátoru vychází
z SGML. První znak '-
' znamená, že identifikátor není
zaregistrován. Znamená to, že není zaručena jeho celosvětová
jednoznačnost. Pro registrované identifikátory se na tomto místě
používá znak '+
'. Pokud je vlastníkem organizace ISO,
uvádí se na začátku řetězec ISO 8879:1986
.
Další část identifikátoru označuje organizaci nebo osobu, která je vlastníkem souboru označeného veřejným identifikátorem. Například pro HTML má identifikátor tvar
-//W3C//DTD HTML 4.0 Transitional//EN
Na první pohled vidíme, že vlastníkem je konsorcium W3C. U DocBooku je to zase firma Oasis.
Za dalšími dvěma lomítky následuje určení typu souboru. V našem
případě tam bude vždy DTD, protože se odkazujeme na soubor s DTD. Poté
následuje textové označení dokumentu -- například DocBook
V3.1
pro verzi 3.1 systému DocBook. Za posledními dvěma lomítky
je kód jazyka, ve kterém je DTD zapsáno. Nejčastěji se setkáme s kódem
EN
, který odpovídá angličtině.