XML – ćwiczenia 5: XML Schema

Przypominamy, że standard XML Schema zdefiniowany jest w trzech rekomendacjach:

Klucze i referencje

Wartości unikalne i klucze

XML Schema pozwala wymusić, by pewne wartości w dokumencie były unikalne. Do wymuszania unikalności służą elementy schematu: unique i key. Opisy w rekomendacji: Primer, Structures.

Podelement selector określa zakres, w jakim wartości mają być unikalne. Podelement field określa wartość, która ma być unikalna. Może być wiele podelementów field – wówczas unikalna musi być krotka wartości (i ona stanowi wartość klucza). Zakres oraz wartości określa się za pomocą wyrażeń XPath, przy czym nie wszystkie wyrażenia są tu dopuszczalne. W szczególności selektorem może być jedynie zbiór elementów, a polami całe elementy i atrybuty, nie można uzywać predykatów ani osi innych niż child i attribute.

Wyrażenie w selector wskazuje w dokumencie zbiór elementów. Dla każdego z tych elementów wartość wyrażenia z każdego field musi wyliczyć się do dokładnie jednego elementu lub atrybutu z prostym typem zawartości. Dla key każda z tych wartości dodatkowo musi być niepusta. Krotki wartości z field, które mają wszystkie wartości niepuste, muszą być parami różne.

Przykład 1.

<xs:unique name="studenci_unique">
	<xs:selector xpath="studenci/student"/>
	<xs:field xpath="imie"/>
	<xs:field xpath="nazwisko"/>
</xs:unique>

<xs:key name="studenci_key">
	<xs:selector xpath="studenci/student"/>
	<xs:field xpath="nr-indeksu"/>
</xs:key>

Referencje

W XML Schema można także wymusić, aby pewne wartości w dokumencie były równe wartościom występującym w innym miejscu dokumentu.

Mówiąc precyzyjnie, można określić, że pewna wartość (krotka wartości) jest referencją do klucza (key lub unique) zdefiniowanego w tym samym schemacie. Krotność klucza i referencji muszą się zgadzać.

Przykład 2.

<xs:keyref name="grupy_studenci_ref" refer="studenci_key">
	<xs:selector xpath="grupy/grupa/student"/>
	<xs:field xpath="@ref"/>
</xs:keyref>

Klucze i referencje w stylu DTD

Definiowanie kluczy i referencji jest możliwe także w DTD, jednak w bardzo ograniczony sposób.

Atrybuty mogą posiadać typ ID. Wartością takiego atrybutu może być tylko nazwa (m.in. musi zaczynać się od litery). Dla danej nazwy elementu tylko jeden atrybut może posiadać typ ID. W całym dokumencie wszystkie atrybuty o typie ID muszą posiadać unikalne wartości.

Atrybuty mogą posiadać typ IDREF. Wartością takiego atrybutu może być tylko nazwa. Nazwa ta musi występować gdzieś w dokumencie jako wartość atrybutu i tyie ID.

Jak widać technika ta jest bardzo ograniczona. M.in. kluczami nie mogą być elementy, identyfikatorami mogą być tylko nazwy, identyfikatory muszą być unikalne w skali całego dokumentu.

Typy ID i IDREF wsytępują w XML Schema dla zachowania kompatybilności z DTD, ale, o ile nie jest to konieczne, nie należy ich używać, a do definiowania kluczy i referencji należy stosować key i keyref.

Przykład schematu i dokumentu.

Zadanie 1.

Do schematu uczelnia.xsd dodaj listę przedmiotów i sal.

Zadanie 2.

Niech numer sali będzie jej kluczem, a przedmioty niech mają sztuczny klucz jako atrybut. Dodatkowo nazwy przedmiotów niech będą unikalne.

Zadanie 3.

Zdefiniuj element termin-zajec zawierający informacje o sali, w jakiej zajęcia się odbywają (referencja), oraz terminie zajęć (dzień tygodnia, godziny rozpoczęcia i zakończenia).

W grupach dodaj referencje do przedmiotów i podelementy termin-zajec.

Modyfikowanie typów

XML Schema pozwala na tworzenie typów na podstawie innych, już zdefiniowanych typów deriving types. Dzięki temu schematy mogą być bardziej strukturalne i rozszerzalne.

Możliwe jest rozszerzanie typów złożonych oraz zawężanie typów złożonych i prostych. Warto zaznaczyć, że rozszerzanie i zawężanie nie są tu operacjami przeciwnymi. Rozszerza się strukturę, np. o nowe podelementy, a zawęża dopuszczalny zbiór wartości, poprzez dodawanie lub wzmacnianie ograniczeń.

Przykłady w ramkach pochodzą z rekomendacji Primer, poza tym jeden przykład, do zadań.

Zawężanie typów prostych

Zawężanie typów prostych było omówione na poprzednich zajęciach. Z zawężaniem typów prostych wiąże się pojęcie facet.

Typ złożony z typu prostego

Aby zawartość elementu była typu prostego, ale element ten posiadał atrybuty, należy utworzyć typ złożony z prostą zawartością.

Opis w rekomendacji: nieformalny i formalny.

Przykład 3.

<xsd:element name="internationalPrice">
  <xsd:complexType>
    <xsd:simpleContent>
      <xsd:extension base="xsd:decimal">
        <xsd:attribute name="currency" type="xsd:string"/>
      </xsd:extension>
    </xsd:simpleContent>
  </xsd:complexType>
</xsd:element>

Rozszerzanie typów złożonych

Rozszerzanie typów złożonych bardzo przypomina dziedziczenie klas w obiektowych językach programowania. Do typu podstawowego można dodać kolejne podelementy i atrybuty, tak jak do klas dodaje się pola i metody.

Model typu podstawowego i model z rozszerzenia są ustawiane jeden po drugim w sekwencji.

Opis w rekomendacji: nieformalny i formalny.

Przykład 4.

Przykład z rekomendacji.

<complexType name="Address">
    <sequence>
      <element name="name"   type="string"/>
      <element name="street" type="string"/>
      <element name="city"   type="string"/>
    </sequence>
  </complexType>

  <complexType name="UKAddress">
    <complexContent>
      <extension base="ipo:Address">
        <sequence>
          <element name="postcode" type="ipo:UKPostcode"/>
        </sequence>
        <attribute name="exportCode" type="positiveInteger" fixed="1"/>
      </extension>
    </complexContent>
  </complexType>

Daje to nastepujący wynikowy model zawartości:

<complexType name="UKAddress">
  <sequence>
    <!-- content model of Address -->
    <element name="name"   type="string"/>
    <element name="street" type="string"/>
    <element name="city"   type="string"/>

    <!-- appended element declaration -->
    <element name="postcode" type="ipo:UKPostcode"/>
  </sequence>

  <!-- appended attribute declaration -->
  <attribute name="exportCode" type="positiveInteger" fixed="1"/>
</complexType>

Zawężanie typów złożonych

Zawężanie typów złożonych polega na nałożeniu na typ dodatkowych ograniczeń lub wzmocnieniu istniejących.

Opis w rekomendacji: nieformalny i formalny.

Przykład 5.

<complexType name="PurchaseOrderType">
    <sequence>
      <element name="shipTo"     type="ipo:Address"/>
      <element name="billTo"     type="ipo:Address"/>
      <element ref="ipo:comment" minOccurs="0"/>
      <element name="items"      type="ipo:Items"/>
    </sequence>
    <attribute name="orderDate" type="date"/>
  </complexType>
  
  <complexType name="RestrictedPurchaseOrderType">
  <complexContent>
    <restriction base="ipo:PurchaseOrderType">
      <sequence>
        <element name="shipTo" type="ipo:Address"/>
        <element name="billTo" type="ipo:Address"/>
        <element ref="ipo:comment" minOccurs="1"/>
        <element name="items"  type="ipo:Items"/>
      </sequence>
    </restriction>
  </complexContent>
</complexType>

Przykłady innych możliwych ograniczeń w tabeli.

Zadanie 4.

Stwórz typ PracownikTyp jako rozszerzenie (lub zawężenie...) typu OsobaTyp, w którym atrybut email jest obowiązkowy oraz występuje dodatkowy sztuczny identyfikator.

Zadanie 5.

Zdefiniuj element pracownik o tym typie. Do dokumentów dodaj listę pracowników.

Zadanie 6.

Do informacji o przedmiocie oraz o grupie dodaj referencję do prowadzącego,


Valid XHTML 1.1Valid CSS