Laboratorium XML
wtorek 11.00—12.30
»Home
»Materiały
  »DTD & co.
  »SAX
  »DOM
  »Zadanie 2
  »XPath
  »XSLT
  »Simple
  »JDOM
  »JS
»Odnośniki
  »Xerces2
»Zadania

Deklaracja typu dokumentu (DTD)

Standard XML określa dwa rodzaje poprawności:

  1. well-formed, tzn. dokument jest dobrze sformułowany w sensie poprawnego zapisu znaczników czyli, m.in.

    1. Znaczniki otwierające, zamykające i puste są poprawne strukturalnie

    2. Znaczniki są poprawnie zagnieżdżone

    3. Dokument posiada dokładnie jeden znacznik główny (root)

    Do sprawdzania poprawności na poziomie well-formed używaliśmy komendy

    $ xmllint nazwa.xml
  2. valid tzn. dokument jest zgodny z deklaracją typu dokumentu (DTD) w tym celu dokument musi, m.in.

    1. Zawierać deklarację typu

    2. Wszystkie znaczniki (elementy), ich zawartość oraz atrybuty są zgodne z zadeklarowanym typem dokumentu.

    Do sprawdzania poprawności na poziomie valid używamy komendy

    $ xmllint --valid nazwa.xml

Deklaracje wewnętrzne i zewnętrzne

Deklaracja typu dokumentu występuje po deklaracji dokumentu XMLowego <?xml … ?>, a przed elementem korzenia dokumentu i może mieć postać

  1. deklaracji wewnętrznej (osadzonej w dokumencie) :

    <!DOCTYPE NazwaElementuRoot [ DeklaracjeZnacznikówAtrybutówIEncji ]>
  2. deklaracji zewnętrznej określonej, albo przez adres URI, albo nazwę (w systemowym katalogu typów dokumentów) i adres URI:

    <!DOCTYPE NazwaElementuRoot SYSTEM "../file.dtd">
    <!DOCTYPE NazwaElementuRoot SYSTEM "http://example.com/file.dtd">
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
        "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

Przykład: Okno ,,Ustawienia panelu''

W dalszym ciągu omówimy języki deklaracji typu dokumentów DTD i XML Schema na przykładzie okna Ustawienia panelu zapisanego w języku XUL (XML User Interface Language). Okno wygląda następująco:

window1.xul

i jest opisane plikiem window1.xul:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
    id="findfile-window"
    title="Ustawienia panelu"
    orient="vertical"
    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

  <groupbox>
    <caption label="Rozmiar panelu"/>
    <radiogroup>
      <radio label="Mały" selected="true"/>
      <radio label="Średni"/>
      <radio label="Duży"/>
    </radiogroup>
  </groupbox>
  <!-- NOTE: right is deprecated, but end does not work in my firefox -->
  <hbox align="right">
  <button id="cancel-button" label="Cancel" oncommand="window.close()"/>
  <button id="find-button" label="Ok" oncommand="window.close()"/>
  </hbox>

</window>

Następnie sformułujemy typ dokumentu DTD dla window1.xul (okrojony język XUL):

<!-- okrojony język XUL -->

<!ENTITY letterA "&#65;">
<!ENTITY digit4 "&#x34;">
<!ENTITY % widget "button|groupbox|hbox|vbox|radiogroup|radio">

<!ELEMENT window (%widget;)*>
<!ATTLIST window
          id ID #IMPLIED
          title CDATA #IMPLIED
          orient (horizontal|vertical) "vertical"
          xmlns CDATA #IMPLIED>

<!ELEMENT groupbox (caption?,(%widget;)*)>

<!ELEMENT radiogroup (%widget;)*>

<!ELEMENT hbox (%widget;)*>
<!ATTLIST hbox
          align (start|center|end|baseline|left|right) "start">

<!ELEMENT vbox (%widget;)*>
<!ATTLIST vbox
          align (start|center|end|baseline|left|right) "start">

<!ELEMENT button EMPTY>
<!ATTLIST button
          id ID #IMPLIED
          label CDATA #REQUIRED
          oncommand CDATA #IMPLIED>

<!ELEMENT radio EMPTY>
<!ATTLIST radio
          label CDATA #REQUIRED
          selected (false|true) "false">

<!ELEMENT caption EMPTY>
<!ATTLIST caption
          label CDATA #REQUIRED>

Następnie sformułujemy typ dokumentu XML Schema dla window1.xul (okrojony język XUL):

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:win="http://math.univ.gda.pl/~lpankows/xml-wtorek/window1.xsd"
            targetNamespace="http://math.univ.gda.pl/~lpankows/xml-wtorek/window1.xsd">

<xsd:annotation>
  <xsd:documentation xml:lang="pl">
    okrojony język XUL
  </xsd:documentation>
</xsd:annotation>

<xsd:group name="widget">
  <xsd:choice>
    <xsd:element ref="button"/>
    <xsd:element ref="groupbox"/>
    <xsd:element ref="hbox"/>
    <xsd:element ref="vbox"/>
    <xsd:element ref="radiogroup"/>
    <xsd:element ref="radio"/>
  </xsd:choice>
</xsd:group>

<xsd:element name="window" type="Window"/>

<xsd:complexType name="Window">
  <xsd:group ref="widget" minOccurs="0" maxOccurs="unbounded"/>
  <xsd:attribute name="id" type="xsd:ID"/>
  <xsd:attribute name="title" type="xsd:string"/>
  <xsd:attribute name="orient" type="xsd:string"/>
</xsd:complexType>

<!-- Pusty typ złożony, tzn. tylko atrybuty  -->
<xsd:element name="button">
  <xsd:complexType>
    <xsd:attribute name="id" type="xsd:ID"/>
    <xsd:attribute name="label" type="xsd:string" use="required"/>
    <xsd:attribute name="oncommand" type="xsd:string"/>
  </xsd:complexType>
</xsd:element>

<xsd:element name="radiogroup">
  <xsd:complexType>
    <xsd:group ref="widget" minOccurs="0" maxOccurs="unbounded"/>
  </xsd:complexType>
</xsd:element>

<xsd:element name="radio">
  <xsd:complexType>
    <xsd:attribute name="label" type="xsd:string" use="required"/>
    <xsd:attribute name="selected" type="xsd:boolean" default="false"/>
  </xsd:complexType>
</xsd:element>

<xsd:complexType name="XBox">
  <xsd:group ref="widget" minOccurs="0" maxOccurs="unbounded"/>
  <xsd:attribute name="align">
    <xsd:simpleType>
      <xsd:restriction base="xsd:string">
        <xsd:enumeration value="start"/>
        <xsd:enumeration value="center"/>
        <xsd:enumeration value="end"/>
        <xsd:enumeration value="baseline"/>
        <xsd:enumeration value="left"/>
        <xsd:enumeration value="right"/>
      </xsd:restriction>
    </xsd:simpleType>
  </xsd:attribute>
</xsd:complexType>

<xsd:element name="hbox" type="XBox"/>
<xsd:element name="vbox" type="XBox"/>

<xsd:complexType name="Caption">
  <xsd:simpleContent>
    <xsd:extension base="xsd:string">
      <xsd:attribute name="label" type="xsd:string"/>
    </xsd:extension>
  </xsd:simpleContent>
</xsd:complexType>

<xsd:element name="groupbox">
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element name="caption" type="Caption" minOccurs="0"/>
      <xsd:group ref="widget" minOccurs="0" maxOccurs="unbounded"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>

</xsd:schema>

Poprawność tego schematu można sprawdzić komendą (wymaga usunięcia atrybutu xmlns elementu window z pliku windows1.xul):

$ xmllint --schema window1.xsd window1.xul

Poza konstrukcjami występującymi w powyższym przykładzie w zadaniu mogą też przydać się ograniczenie zakresu liczb:

<!-- Patrz tryb wbudowany gMonth -->
<xsd:simpleType name="NumerMiesiąca">
  <xsd:restriction base="xsd:integer">
    <xsd:minInclusive value="1"/>
    <xsd:maxInclusive value="12"/>
  </xsd:restriction>
</xsd:simpleType>

oraz typ łańcuchowy zadany wyrażeniem regularnym:

<xsd:simpleType name="NumerDowodu">
  <xsd:restriction base="xsd:string">
    <xsd:pattern value="[A-Z]{2} \d{7}"/>
  </xsd:restriction>
</xsd:simpleType>

Zadanie do oddania: Zamówienie na książki, CD i DVD

Napisać przykładowy dokument XMLowy zad1.xml, deklarację typu DTD zad1.dtd oraz deklarację typu XML Schema zad1.xsd. Dokument powinien mieć następującą strukturę (typ):

Zamówienie (nr zamówienia: wymagany) {
        Adres Dostarczenia (termin dostrczenia, tzn. data) {
                Nazwa, Ulica, Kod pocztowy, Miasto, [Kraj FIXED Polska];
        }
        Adres Dostarczenia faktury {
                Jak wyżej albo tylko jeden element -- adres email;
        }
        Artykuły {
                // od 1--100
                Artykuł (ilość: 1--100: opcjonalny, domyślnie 1;
                         unikalny identyfikator: wymagany) {
                        // dokładnie jedno z:
                        // książka, muzyczna płyta CD albo filmowa płyta DVD
                        Książka {
                                Tytuł, Autor, Nazwa wydawnictwa, Rok wydania,
                                        Numer wydania, Numer ISBN;
                        }
                        CD {
                                Nazwa albumu, Wykonawca, Wydawca, Rok wydania,
                                        Opcjonalny czas trwania;
                        }
                        DVD {
                                Tytuł, Reżyser, Wytwórca/Dystrybutor, Rok premiery,
                                       Opcjonalny czas trwania;
                        }
                }
        }
}

gdzie () oznacza atrybuty dozwolone dla danego elementu elementu, zaś {} zagnieżdżone elementy. Przykładowy dokument zad1.xml powinien zawierać: co najmniej po jednej książce, CD i DVD (mile widziane rzeczywiste dane).

Proszę zwrócić uwagę na typy danych atrybutów i elementów, np. w formacie który na to zezwala proszę odpowiednio zdefiniować: Kod pocztowy, Numer ISBN (np. "ISBN 83-01-12641-8") oraz typy lub zakresy liczbowe.

Rozwiązania proszę w ciągu tygodnia (przed następnymi zajęciami) wysłać na adres lukpank-at-o2.pl z tytułem [xml-wtorek] zad1 z trzema załącznikami (zad1.xml, zad1.dtd i zad1.xsd). Przed wysłaniem Proszę upewnić się, że przykładowy dokument jest poprawny w myśl obu definicji, tzn. komendy

$ xmllint --valid zad1.xml
$ xmllint --schema zad1.xsd zad1.xml

wykonują się bez błędu. Po wysłaniu rozwiązania powinni państwo otrzymać automatyczną odpowiedź, że zadanie zostało przyjęte i jest poprawne (lub nie) wedle powyższych komend (automatyczna odpowiedź nie będzie działała (nie przyjdzie) przed czwartkiem).