DTD

Koziołek

1 Podstawowe informacje
2 Składnia pliku DTD
     2.1 XML wykorzystywany w reszcie artykułu
     2.2 !ELEMENT opis elementów dokumentu XML
          2.2.1 Liczność elementów
          2.2.2 Grupowanie elementów, elementy warunkowe
     2.3 !ATTLIST opis atrybutów elementu
     2.4 !ENTITY, !NOTATION, zbiory wartości
          2.4.3 Encje
          2.4.4 Zbiory wartości
          2.4.5 Notacja
     2.5 Wartości dozwolone dla elementów i atrybutów

DTD - ang. Document Type Definition - definicja typu dokumentu. Jest to dokument zawierający definicję dokumentu zgodnego z SGML.

Innymi słowy opisuje on zależności pomiędzy poszczególnymi elementami, tagi, atrybuty, dokumentu SGML (XML, HTML). Jest to starszy sposób opisu dokumentu XML. Nowszą , zalecaną, metodą do opisania dokumentu XML jest użycie XML Schema (XSD).

Podstawowe informacje

DTD jest plikiem tekstowym w kodowaniu podanym w pierwszej linii pliku w postaci:

<?xml encoding="UTF-8"?>

Tu używamy UTF-8.

Składnia pliku jest stosunkowo prosta. W pliku mogą pojawić się trzy główne elementy:

  1. komentarze w postaci znanej z XML.
  2. elementy !ELEMENT zawierające opis tagu.
  3. elementy !ATTLIST zawierające opis atrybutów.

Dodatkowo można zdefiniować elementy ułatwiające notację lub też ją skracające:

  1. !ENTITY definijący encję.
  2. NOTATION definiujący grupę.

Dla przykładowego pliku XML;

<!DOCTYPE root SYSTEM "root.dtd">
<root attibute="test" />

plik root.dtd może wyglądać następująco:

<!ELEMENT root EMPTY >
<!ATTLIST root
   attibute CDATA #REQUIRED
>

Ścieżka do pliku DTD może być obliczana na kilka sposobów, ale co do zasady jeżeli nie jest adresem URL parser wyznaczy ją jako ścieżkę względną do położenia dokumentu. W naszym przykładzie oznacza to, że pliki root.xml i root.dtd muszą znajdować się w tym samym katalogu.

Składnia pliku DTD

XML wykorzystywany w reszcie artykułu

Poniższy plik XML będzie wykorzystywany w reszcie artykułu.

<!DOCTYPE biblioteka SYSTEM "biblioteka.dtd">
<biblioteka>
   <ksiazki>
        <ksiazka id="k1" tytul="Słownik Pijacki">
            <autor id="a1">
               <imie>Julian</imie>
               <nazwisko>Tuwim</nazwisko>
            </autor>
        </ksiazka>
        <ksiazka id="k2" autor="a2" tytul="Bajki" />
        <ksiazka id="k3" tytul="Matematyka Poradnik encyklopedyczny">
           <autorzy>
              <autor id="a3">
                 <nazwisko>Bronsztejn</nazwisko>
               </autor>
              <autor id="a4">
                 <nazwisko>Siemiendiajew</nazwisko>
               </autor>
           </autorzy>
        </ksiazka>
  </ksiazki>
  <autorzy>
        <autor id="a2">
            <imie>Jean</imie>
            <nazwisko>de La Fontaine</nazwisko>
         </autor>
  </autorzy>
</biblioteka>

Na jego podstawie będziemy stopniowo tworzyć dokument DTD.

!ELEMENT opis elementów dokumentu XML

Podstawowym budulcem dokumentu XML są elementy zwane potocznie tagami. Definiując tag w DTD należy użyć bloku !ELEMENT. Składa się on z dwóch elementów. Pierwszym z nich jest nazwa tagu, drugim zawartość:

<!ELEMENT nazwa_tagu zawartość >

Nazwa tagu może być dowolna, ale musi spełniać kilka założeń:

  1. Nazwa składa się z małych i dużych liter, liczb oraz innych znaków, ale
  2. nazwa nie może zawierać spacji,
  3. nazwa nie może zaczynać się od cyfry lub znaku interpunkcyjnego.
  4. Nazwa nie może zaczynać się od ciągu XML (niezależnie od wielkości liter).
  5. Nazwy tagów rozróżniają wielkość liter. Tag i tag to dwa różne tagi.

Warto też przestrzegać dwóch nieoficjalnych reguł:

  1. Używać nazw znaczących.
  2. Używać tylko znaków ASCII.

Pierwsza z nich jest jasna. XML służy do opisu danych, a nazwy tagów stanową jedną z danych. Jeżeli są znaczące znacznie prościej tworzyć i czytać dokumenty XML. Druga zasada wynika z praktyki. Nie wiadomo jak na kodowanie znaków nie należących do ASCII zareaguje kod klienta. W teorii powinien prawidłowo przetworzyć dokument kierując się danymi z nagłówka. W praktyce różnie z tym bywa. Dodatkowo nie każdy program do obsługi XML używa czcionek zdolnych wyświetlić znaki z poza ASCII.

Przystąpmy do tworzenia pliku biblioteka.dtd. Naszym pierwszym krokiem będzie zdefiniowanie tagu - korzenia drzewa XML. Analizując dokument biblioteka.xml wiemy, że jest to element biblioteka, którzy powinien zawierać dokładnie jeden element ksiazki i dokładnie jeden elementautorzy w tej kolejności.

<!-- Document root -->
<!ELEMENT biblioteka (ksiazki,autorzy)>

Liczność elementów

Każdy element może zawierać zero lub więcej innych elementów. Muszą być one podane w nawiasie po nawie taga i przed zakończeniem !ELEMENT. Może też być pusty. Czasami istnieje potrzeba zdefiniowania minimalnej bądź maksymalnej ilości wystąpienia jakiegoś tagu w innym tagu. DTD udostępnia bardzo uproszczony mechanizm określania liczności. Opiera się ona na pewnych elementach składni wyrażeń regularnych.

  1. Jeżeli chcemy by dany tag wystąpił tylko raz to po nazwie elementu nie dodajemy żadnego znaku.
  2. Jeżeli chcemy by dany tag wystąpił co najmniej raz należy po nazwie dodać znak +.
  3. Jeżeli chcemy by dany tag wystąpił raz lub nie wystąpił w ogóle należy po nazwie dodać znak ?.
  4. Jeżeli chcemy by dany tag wystąpił lub nie wystąpił w ogóle należy po nazwie dodać znak *.
  5. Jeżeli dany element ma być pusty jako zawartość podajemy słowo EMPTY.
  6. Jeżeli dany element może zawierać dowolny inny tag jako zawartość podajemy słowo ANY.

Dokładny opis wartości jakie może przyjmować zbiór elementów zawartych w danym tagu znajdziesz w części DTD#id-Wartości dozwolone dla elementów i atrybutów.

Oczywiście elementy mogą zawierać kombinacje innych elementów w dowolny sposób. Niestety DTD nie jest na tyle elastyczne by uzależniać występowanie elementów od występowania atrybutów.
Uzupełnijmy teraz nasz plik DTD o definicje elementów ksiazki i autorzy:

<!-- Document root 					-->
<!ELEMENT biblioteka (ksiazki,autorzy)>

<!-- biblioteka 					-->
<!-- 	|-ksiazki   				-->
<!ELEMENT ksiazki (ksiazka*)>

<!-- biblioteka 					-->
<!-- 	|-autorzy   				-->
<!ELEMENT autorzy (autor*)>

Grupowanie elementów, elementy warunkowe

Popatrzmy jeszcze raz na naszego XMLa. Załóżmy, że można składować autorów jako elementy ksiązki, ale też jako osobne autonomiczne twory. Przykładem takiego założenia jest autor, który napisał tylko jedną książkę. Można go wtedy zapisać przy tej książce. Jeżeli jednak mamy wiele ksiażek tego samego autora warto go przenieść w jakieś inne miejsce, które będzie łatwiej dostępne z innych punktów aplikacji. Innym przykładem jest HTMLowy tag samp, który może występować w różnych innych tagach. Chcemy jednak, aby jeżeli dodamy tag autor do książki nie można było dodać tagu autorzy i odwrotnie. Jeżeli dodamy tag autorzy nie można było dodać tagu autor.
Wchodzimy tu na grząski grunt definiowania grup elementów i uzależniania ich występowania od występowania innych elementów. Na początek zdefiniujmy element autor i jego podelementy.

<!-- biblioteka 					-->
<!-- 	|-autorzy   				-->
<!-- 	     |-autor 				-->
<!ELEMENT autor (imie*,nazwisko+)>

<!-- biblioteka 					-->
<!-- 	|-autorzy   				-->
<!-- 	     |-autor 				-->
<!-- 		     |-imie 			-->
<!ELEMENT imie (#PCDATA)>

<!-- biblioteka 					-->
<!-- 	|-autorzy   				-->
<!-- 	     |-autor 				-->
<!-- 		     |-nazwisko			-->
<!ELEMENT nazwisko (#PCDATA)>

Zastosowaliśmy liczność elementów. Autor może nie mieć imienia (Bronsztejn, Siemiendiajew), ale musi mieć nazwisko. Założylismy też, że najpierw podajemy imie/imiona, a następnie nazwisko/nazwiska. Przejdźmy zatem do opisania książki jako elementu. Jej fragment DTD będzie wyglądał w następujacy sposób:

<!-- biblioteka 					-->
<!-- 	|-ksiazki   				-->
<!-- 	     |-ksiazka 				-->
<!ELEMENT ksiazka ((autorzy|autor)?)>

Zapis ten należy rozumieć w następujący sposób. W elemencie ksiazka może wystepować conajwyżej jeden element ze zbioru autorzy,autor.
Poeksperymentuj z zapisem DTD w narzędziach takich jak Open XML Editor, Cooktop czy płatnym XMLSpy (30 dniowy, darmowy trial).
Zamiast innego elemntu można oczywiście podać inne wartości. Ich dokładny opis znajdziesz na końcu tego tekstu w części DTD#id-Wartości dozwolone dla elementów i atrybutów. Teraz przyjrzymy się dokładniej atrybutom i ich definiowaniu w ramach DTD.

!ATTLIST opis atrybutów elementu

Każdy tag XML może zawierać atrybuty. Ich definiowanie w ramach DTD odbywa się poprzez element !ATTLIST. Po nazwie elemntu następuje nazwa tagu dla którego definiujemy atrybuty, a następinie lista definicji atrybutów. Poniżej definicja atrybutów dla elementu ksiazka:

<!ATTLIST ksiazka
	id ID #REQUIRED
	tytul CDATA #REQUIRED
	autor IDREFS #IMPLIED
>

Definicja atrybutu składa się z trzech elementów. Po pierwsze jest to jego nazwa. Następnie następuje definicja typu atrybutu, która opiuje nie tylko dostolone wartości atrybutu, ale też ich sens (czy są identyfikatorami, wskazują na identyfikatory). Na koniec wystepuje wskazanie obowiązkowości atrybutu oraz jego wartości domyślnej. Atrybut może też przyjmować tylko jedna wartość w takim przypadku używane jest słowo #FIXED. Poniżej fragment DTD dla dokumentu, w którym atrybuty mają wartość domyślną jak i przyjmuja tylko jedną wartość:

<!ATTLIST inwestycja
	wirtualizacja CDATA #FIXED "false"
	polozenie CDATA "plan"
>

Nazwy atrybutów podlegają takim samym zasadą jak nazwy elementów. Wartości atrybutów znajdziesz w części DTD#id-Wartości dozwolone dla elementów i atrybutów.

!ENTITY, !NOTATION, zbiory wartości

Encje

Wraz z rozwojem XMLa pojawiła się konieczność zapisywania niektorych znaków specjalnych w dokumentach. Znakiem, który może być trudny w zapisie "z klawiatury", a jednocześnie dość często występuje w tekstach jest znak copyright - ©. Zapewne niewielu ludzi potrafiło by zapisać ten znak bez odwoływania się do tablicy znaków (w tablicy UTF-8 jest to U+00A9 - 0xC209). Dlatego też można zdefiniować pewne ciągi, znaki czy frazy jako specjalne elementy dokumentu XML - encje.
Encje dzielimy na encje lokalne, globalne, parametrowe. Encje lokalne definiowane są w ramach danego DTD i mogą być używane w dokumentach XML odwołujących się do danego DTD. Ich definicja wygląda w następujący sposób:

<!ENTITY copyright "©">

Chcąc użyć encji w dokumencie XML należy zapisać je jako &copyright;, ogólnie &nazwa encji;.

Encje globalne to odmiana encji lokalnej, która jako wartość przyjmuje treść dokumentu XML:

<!ENTITY licence SYSTEM "http://www.gnu.org.pl/text/licencja-gnu.html">

Encja taka w niczym nie rożni się od encji lokalnej i jest używana w taki sam sposób.
Osobną grupę stanowią encje parametrowe. Ich zastosowanie jest trochę niejasne, ale w znaczący sposób ułatwia proces tworzenia dokumentu DTD. Encja parametrowa może być wykorzystana tylko w ramach dokumentu DTD w którym została zdefinowana. Innymi słowy encje te po zdefiniowaniu można używać do definiowania innych elementów w dokumencie DTD, ale nie można ich używać poza nim. Poniżej przykład użycia encji parametrowej do zdefiniowania zawartości tagu ksiazka:

<!-- biblioteka 					-->
<!-- 	|-ksiazki   				-->
<!-- 	     |-ksiazka 				-->
<!ELEMENT ksiazka (autorzylubautor)>
<!ENTITY % autorzylubautor "(autorzy|autor)?" >

Do czego można wykorzystać tego typu encje? Przede wszystkim w złozonych dokumentach DTD pozwalają one na grupowanie definicji dotyczących wielu tagów w jedną zgrabną i krótką całość. Doskonałym przykładem jest tu DTD dla HTMl, gdzie grupowane są na przykład elementy blokowe, elementy formularza czy też elementy liniowe. Jako że w HTMLu tagi mogą zawierać się w najprzeróżniejszych kombinacjach zatem zamiast definiować taką samą grup w wielu miejscach definiowana jest ona raz.

Zbiory wartości

Czasami przydatną rzeczą jest możliwość skorzystania z ograniczonej liczby wartości. Przykładem może być tu wartość prawda/fałsz. Definiowanie takich wartości odbywa się poprzez stworzenie odpowiednich elementów w ramach definiowania atrybutu. Przykład definicji prawda/fałsz:

<!ATTLIST uczen
	obecny (tak|nie) "nie"
>

Notacja

Gdy istnieje konieczność stworzenia zapisu pozwalającego na odwołanie do zasobu definiowanego w ramach systemu można użyć notacji. Notacja zazwyczaj jest używana do łączenia elemntów dokumentu z typem MIME:

<!NOTATION GIF SYSTEM "image/gif">
<!NOTATION JPG SYSTEM "image/jpeg">
<!NOTATION PNG SYSTEM "image/png">
<!ATTLIST fotografia
	type NOTATION (GIF | JPG | PNG) #IMPLIED>

W takim przypadku atrybut typ może przyjąć jedną z trzech wartości, które reprezentują sobą pewne definicje ogólnosystemowe.

Wartości dozwolone dla elementów i atrybutów

Poniżej lista wartości dozwolonych dla atrybutów i elementów. Definiują one ogólne typy danych i nie są tak dokładne jak XSD, gdzie można używać wyrażeń regularnych.

  1. EMPTY - oznacza pusty element. Atrybuty nie mogą być puste.
  2. PCDATA - w ogólności oznacza wszystkie dane tekstowe. Jeżeli element zawiera tego typu dane to są one parsowane przez procesor XML.
  3. CDATA - oznacza to samo co PCDATA, ale dane nie są parsowane.
  4. NMTOKEN - atrybut przyjmuje wartość składająca się z liter, cyfr i znaków _. Inne znaki są niedopuszczalne.
  5. NMTOKENS - lista wartości NMTOKEN rozdzielonych przecinkami.
  6. ANY - dowolny element.
  7. ID - oznacza identyfikator. Identyfikatory są unikalne w obrębie całego dokumenty. To znaczy, że żadne dwa elementy nie mogą mieć takiego samego identyfikatora niezależnie czy są to takie same elementy czy nie. Identyfikator nie może zawierać spacji.
  8. IDREF - pojedyncze odwołanie do identyfikatora elementu.
  9. IDREFS - lista identyfikatorów rozdzielona spacjami.
XML

1 komentarz

"Nowszą , zalecaną, metodą do opisania dokumentu XML jest użycie XSL." Na pewno chodziło Ci tutaj o XSL, a nie o XSD?