Definition von Elementtypen

(Auszug aus "XML Schema" von Eric van der Vlist)

Der nächste Hinweis, den wir einem Schema-Prozessor geben können, unterstützt ihn dabei, den einfachen oder komplexen Typ eines Elements zu bestimmen. Ein Schema-Validierer errät normalerweise den Typ eines Elements anhand seines Namens und der Beschreibung für das Inhaltsmodell seines Elternelements. Das Ergebnis dieses Ratevorgangs kann der Autor eines Instanzdokuments mit Hilfe des Attributs xsi:type außer Kraft setzen, sofern der angegebene neue Typ eine Ableitung durch Einschränkung oder Erweiterung des im Schema-Dokument angegebenen Typs ist. Da dieser Typ durch ein Attribut im Instanzdokument definiert wird, kann dies nur für Elemente geschehen. (Attribute können keine Attribute haben!)

Hier stellt sich die Frage: »Warum würden wir einen Typ im Instanzdokument definieren wollen?« Die Antwort fällt für einfache und für komplexe Typen leicht unterschiedlich aus und hängt auch davon ab, ob wir nur für Validierungszwecke oder aber auch zwecks Datenbindung an einem Schema interessiert sind.

Definition einfacher Typen

Ein Element (oder Attribut) kann zu mehreren verschiedenen einfachen Typen gehören, und eine Ableitung durch Vereinigung ist im allgemeinen ein guter Weg, einen Schema-Validierer den richtigen Typ wählen zu lassen, ohne daß man xsi:type verwenden müßte. Wir können dabei ziemlich weit gehen. Nachdem wir sowohl die Prinzipien der Ableitung durch Vereinigung als auch das Arbeiten mit Mustern kennengelernt haben, definieren wir zur Veranschaulichung einen Vereinigungstyp, der Datumsangaben nach ISO 8601, ein gebräuchliches englisches (»April 2nd, 1998«) und das deutsche (»2. April 1998«) Datumsformat akzeptiert. Wir können anfangen, indem wir ein ISO-Datum ohne Zeitzone, wie unter Die Verwendung vordefinierter einfacher Datentypen besprochen, definieren:

<xs:simpleType name="dateISO">
   <xs:restriction base="xs:date">
      <xs:pattern value="[^:Z]*"/>
   </xs:restriction>
</xs:simpleType>

Das englische Format kann beschrieben werden, indem man unterschiedliche Muster für die Monate mit 31, 30 bzw. 29 Tagen verwendet (Nicht-Schaltjahre decken wir in unserem Beispiel nicht gesondert ab). Die folgende Definition sollte eine ziemlich gute Näherungslösung für Jahre nach Christi Geburt mit höchstens vier Ziffern geben (die Zeilen sind aus Lesbarkeitsgründen umbrochen, die Muster sollten jeweils auf einer einzigen Zeile stehen):

<xs:simpleType name="EnglishDate">
   <xs:restriction base="xs:token">
      <xs:pattern value="(January|March|May|July|August|October|December) ([1-3]?1st|[12]?2nd|[12]?3rd|(30|[12]?[4-9])th),[0-9]{0,4}"/>
      <xs:pattern value="February ([1-2]?1st|[12]?2nd|[12]?3rd|[12]?[4-9]th),[0-9]{0,4}"/>
      <xs:pattern value="(April|June|September|November) ([1-2]?1st|[12]?2nd|[12]?3rd|(30|[12]?[4-9])th),[0-9]{0,4}"/>
   </xs:restriction>
</xs:simpleType>

Nach dem englischen Format sieht das deutsche einfach aus. Dasselbe Prinzip kann auch hier angewendet werden (Zeilenumbrüche sind der Lesbarkeit halber hinzugefügt worden):

<xs:simpleType name="deutschesDatum">
   <xs:restrictionbase="xs:token">
      <xs:pattern value="([1-3][01]|[12]?[1-9])\. (Januar|März|Mai|Juli|August|Oktober|Dezember)\d{0,4}"/>
      <xs:pattern value="([12][01]|[12]?[1-9])\. Februar \d{0,4}"/>
      <xs:pattern value="([12][01]|[12]?[1-9]|30) (April|Juni|September|November)\d{0,4}"/>
      <xs:restriction>
</xs:simpleType>

Der letzte Schritt besteht darin, den Typ wie folgt durch Vereinigung abzuleiten:

<xs:simpleType name="anydate">
  <xs:union memberTypes="dateISO EnglishDate deutschesDatum"/>
</xs:simpleType>

Uns liegt nun ein einfacher Typ vor, der drei verschiedene Datumsformate akzeptiert. Ein Schema-Prozessor sollte nicht nur diese drei Formate validieren, sondern auch im PSVI anzeigen, welchen Typ er erkannt hat. Wir haben dies erreicht, ohne dem Instanzdokument irgend etwas hinzuzufügen. Warum wollen wir dann überhaupt eine derartige Information im Instanzdokument angeben? Dafür gibt es einige gute Gründe. Zum einen wollen wir diese Information auch Anwendungen, die sie nicht aus dem PSVI bekommen können, zur Verfügung stellen. Bei den derzeitigen Tools ist das oft der Fall, da es keine Spezifikation für die Schnittstelle gibt, nach der eine Anwendung das PSVI lesen kann. Dieser Grund liegt nicht vor, wenn wir nur an Validierung interessiert sind. Er kann jedoch wichtig werden, wenn wir Anwendungen, die unsere Instanzdokumente bearbeiten, nicht mit der Prüfung belasten wollen, welches Format sie geliefert bekommen.

Der zweite Grund ist in dem vorangegangenen Beispiel nicht zu erkennen. Da die lexikalischen Räume der verschiedenen Mitgliedstypen sich nicht überlappen, kann kein Durcheinander entstehen. Dies ist nicht immer so. Wir wollen möglicherweise die Wahl, die der Schema-Validierer getroffen hat, außer Kraft setzen, oder wir wollen sogar einen allgemeinen, »universellen« Typ in dem Schema verwenden und uns darauf verlassen, dass die Instanzdokumente definieren, welcher Typ verwendet wird. Eine Art von Anwendungen, die gute Kandidaten für dieses Vorgehen sind, sind Protokoll- oder Bindungsanwendungen, für die XML nur ein temporäres Serialisierungsformat ist. Diese Anwendungen müssen oft generische Elemente definieren, die benutzt werden können, um Parameter beliebigen Typs aufzunehmen.

Beispielsweise kann ein schemabasiertes XML-RPC durch das erste Beispiel der XML-RPC-Spezifikation definiert werden:

<methodCall>
   <methodName>
      examples.getStateName
   </methodName>
   <params>
      <param>
         <value>
            <i4>
               41
            </i4>
         </value>
      </param>
   </params>
</methodCall>

In einer hypothetischen W3C-XML-Schema-fähigen Version von XML-RPC könnte dies durch das folgende ersetzt werden:

<methodCall xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <methodName>
      examples.getStateName
   </methodName>
   <params>
      <param>
         <value xsi:type="xs:int">
            41
         </value>
      </param>
   </params>
</methodCall>

Definition komplexer Typen

Auch wenn der Mechanismus, einen komplexen Typ in einem Instanzdokument mit Zwang zu bestimmen, demjenigen sehr ähnlich ist, den wir bei einfachen Typen gesehen haben, können die Motive für die Verwendung ganz andere sein. Es ist zwar immer noch möglich, diese Konstruktion für einen polymorphen Accessor (um die Terminologie der W3C-Arbeitsgruppe für Protokolle zu verwenden) zu benutzen, doch dürfte dies ein ziemlich seltener Anwendungsfall für komplexe Typen sein, da sie keine Ableitung durch Vereinigung kennen. Was im Bereich der komplexen Typen der Ableitung durch Vereinigung einfacher Typen gleichkäme, wäre die Fähigkeit, mehrere Inhaltsmodelle für ein einziges Element zu definieren, den Schema-Prozessor alle diese Inhaltsmodelle durchprobieren zu lassen und das erste festzuhalten, das auf das Fragment des Instanzdokuments paßt. Das wäre tatsächlich sehr schön, es ist jedoch genau das, was die Regeln von der konsistenten Deklaration und von der eindeutigen Partikelzuordnung ausdrücklich verbieten. Daher gibt es bei komplexen Typen innerhalb des eigentlichen Schemas keinen Gegenkandidaten zu xsi:type. Diese Konstruktion wird jedoch oft zur Umgehung dieser Regeln verwendet.

Ein anderer Weg, sich dies vorzustellen, besteht darin, diese Konstruktion als Hinweis für den Schema-Prozessor zu verstehen, der es diesem erlaubt, eine sich ihm eröffnende Auswahl eindeutig zu entscheiden und so eine Regelverletzung zu vermeiden. Eine typische Verwendung ist demnach die Umgehung der Regel von der eindeutigen Partikelzuordnung, um zwei verschiedene Inhaltsmodelle für dasselbe Element zuzulassen. Wir haben unter Definition von Eindeutigkeit, Schlüsseln und Schlüsselnverweisen gesehen, wie man mit xs:key zulassen könnte, daß der Titel entweder als Attribut oder als Element ausgedrückt werden darf. Diese Umgehungsstrategie hilft jedoch nicht weiter, wenn wir komplexere Kombinationen zulassen wollen, beispielsweise entweder einen als Attribut ausgedrückten Titel oder aber mehrere als Elemente ausgedrückte Titel:

<book id="b3810518883" available="true" title="Auf den Hund gekommen">
   .../...
</book>

oder:

<book id="b3810518883" available="true" type="bookTitleElements">
   <isbn>
      3810518883
   </isbn>
   <title lang="de">
      Auf den Hund gekommen
   </title>
   <title lang="en">
      Being a Dog Is a Full-Time Job
   </title>
   .../...
</book>

Dafür definieren wir einen Basistyp, der eine Obermenge beider Inhaltsmodelle ist:

<xs:complexType name="bookBase">
   <xs:sequence>
      <xs:element ref="isbn"/>
      <xs:element ref="title" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element ref="author" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element ref="character" minOccurs="0" maxOccurs="unbounded"/>
   </xs:sequence>
   <xs:attribute ref="id"/>
   <xs:attribute ref="title"/>
   <xs:attribute ref="available"/>
</xs:complexType>

Dieser Basistyp akzeptiert Buchelemente mit optionalen Titeln, die als Attribute oder als Elemente ausgedrückt sind. Wir können durch Einschränkung einen ersten Typ ableiten, der nur Titelattribute akzeptiert:

<xs:complexType name="bookTitleAttribute">
   <xs:complexContent>
      <xs:restriction base="bookBase">
         <xs:sequence>
            <xs:element ref="isbn"/>
            <xs:element ref="author" minOccurs="0"
               maxOccurs="unbounded"/>
            <xs:element ref="character" minOccurs="0"
               maxOccurs="unbounded"/>
         </xs:sequence>
      </xs:restriction>
   </xs:complexContent>
</xs:complexType>

Wir können einen weiteren Typ ableiten, der nur Titel akzeptiert, die als ein oder mehrere Elemente definiert sind:

<xs:complexType name="bookTitleElements">
   <xs:complexContent>
      <xs:restriction base="bookBase">
         <xs:sequence>
            <xs:element ref="isbn"/>
            <xs:element ref="title" minOccurs="1" maxOccurs="unbounded"/>
            <xs:element ref="author" minOccurs="0" maxOccurs="unbounded"/>
            <xs:element ref="character" minOccurs="0" maxOccurs="unbounded"/>
         </xs:sequence>
         <xs:attribute ref="title" use="prohibited"/>
      </xs:restriction>
   </xs:complexContent>
</xs:complexType>

Nachdem wir nun unsere Bausteine zusammenhaben, verwenden wir sie in dem Schema, um das Buchelelement mit dem Typ bookBase zu definieren:

<xs:element name="book" type="bookBase"/>

Dann können wir sie in den Instanzdokumenten verwenden, um zu deklarieren, welchen abgeleiteten Typ wir benutzen:

<book id="b3810518883" available="true" xsi:type="bookTitleElements">
   <isbn>
      3810518883
   </isbn>
   <title lang="de">
      Auf den Hund gekommen
   </title>
   <title lang="en">
      Being a Dog Is a Full-Time Job
   </title>
   .../...
</book>

oder:

<book id="b3810518883" available="true" title="Auf den Hund gekommen" xsi:type="bookTitleAttribute">
   .../...
</book>

Dies läßt jedoch zu, daß Instanzdokumente den Basistyp benutzen, was wir möglicherweise nicht wollen, weil wir dann vielleicht überhaupt keinen Titel oder aber ein Attribut und zusätzlich ein oder mehrere Elemente haben (was wir vermeiden wollen). Wir können die Verwendung des Basistyps verbieten, indem wir ihn als »abstract« definieren. Wenn wir dieses Attribut in der Definition des komplexen Typs setzen, verhindern wir, daß Instanzdokumente diesen Typ verwenden. Sie müssen statt dessen einen der von ihm abgeleiteten Typen mit dem Attribut xsi:type angeben.

Das Attribut abstract ist sozusagen das Spiegelbild des Attributs block, das wir bereits kennen. Während letzteres weitere Ableitungen verhindert, verlangt ersteres zwingend eine Ableitung. Die endgültige Definition unseres komplexen Basistyps ist somit:

<xs:complexType name="bookBase" abstract="true">
   <xs:sequence>
      <xs:element ref="isbn"/>
      <xs:element ref="title" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element ref="author" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element ref="character" minOccurs="0" maxOccurs="unbounded"/>
   </xs:sequence>
   <xs:attribute ref="id"/>
   <xs:attribute ref="title"/>
   <xs:attribute ref="available"/>
</xs:complexType>

   

<< zurück vor >>

 

 

 

Tipp der data2type-Redaktion:
Zum Thema XML Schema bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:

Copyright © 2003 O'Reilly Verlag GmbH & Co. KG
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "XML Schema" denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

O’Reilly Verlag GmbH & Co. KG, Balthasarstraße 81, 50670 Köln, kommentar(at)oreilly.de