Kontrolle über Ableitungen

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

Es ist an der Zeit, zu den bereits erörterten Konstruktionen zurückzukehren – und neue einzuführen –, um zu erklären, wie man die Verwendung der Ableitungen der verschiedenen Kompositoren steuert. Im wesentlichen bestehen diese Konstruktionen aus Attributen, die es ermöglichen, weitere Ableitungen entweder zu blockieren oder aber Ableitungen vorzuschreiben. Die Feinheit der Abstufung hängt jedoch vom jeweils betroffenen Kompositor ab.

Attribute

Es gibt keine Ersetzungsgruppen für Attribute und keinen Mechanismus, um sie abzuleiten oder ihren Typ in Instanzdokumenten zu definieren. Das bedeutet auch, daß keine Konstruktionen benötigt werden, um ihre Ableitung zu steuern. Um ganz genau zu sein: Es ist möglich, Attribute indirekt abzuleiten, indem ihr Elternelement durch Einschränkung abgeleitet wird oder indem Attributgruppen redefiniert werden.

Elemente

Wenn wir von einem xs:element sprechen, müssen wir zwischen globalen und lokalen Definitionen sowie Referenzen unterscheiden, die sich bezüglich Ableitungen unterscheiden. Eine Kontrolle über Ableitungen wird daher ausgeübt, wie in der folgenden Tabelle gezeigt.

Tabelle: Kontrolle über Elementableitung

AttributGlobales ElementLokale ElementdefinitionElement-Referenz
blockJaJaNein
abstractJaNeinNein
finalJaNeinNein

Block-Attribut

Das Attribut block steuert Typersetzung in den Instanzdokumenten durch das Attribut xsi:type und durch Ersetzungsgruppen. Dieses eine Attribut enthält eine Whitespace-getrennte Liste von Tokens – mit den möglichen Werten »restriction«, »extension« und »substitution« – oder den Spezialwert #all (was für alle drei Werte gemeinsam steht). Der Vorgabewert für das Attribut kann durch das Attribut blockDefault des xs:schema-Dokumentenelements festgelegt werden.

Die ersten beiden Werte (»restriction« und »extension«) steuern jede Ersetzung durch xsi:type oder Ersetzungsgruppen und blockieren die Ersetzung durch Datentypen, die durch Einschränkung oder Erweiterung aus dem Datentyp abgeleitet wurden, der in der Deklaration des Elements definiert worden ist. Der dritte Wert (»substitution«) bezieht sich nur auf die Ersetzungsgruppen und legt fest, ob ein Element aus einer Ersetzungsgruppe (für die das Element der Kopf ist) zulässig ist. Da nur globale Elemente an einer Ersetzungsgruppe teilnehmen können, hat dieser letzte Wert offensichtlich nur für globale Definitionen eine Bedeutung.

Die Tatsache, daß das Attribut block sowohl für Typersetzung als auch für Ersetzungsgruppen verwendet wird, kann in die Irre führen, besonders bei den Werten »restriction« und »extension«, die bei beiden Aspekten Auswirkungen zeigen. Ein einfaches Beispiel konkretisiert dies. Nehmen wir an, wir haben die Definition eines komplexen Typs (personType), der eine Person mit einem Namen, einem erforderlichen Geburtsdatum und optional einem Sterbedatum und einer Charakterisierung angibt:

<xs:complexType name="personType">
   <xs:sequence>
      <xs:element ref="name"/>
      <xs:element ref="born"/>
      <xs:element ref="dead" minOccurs="0"/>
      <xs:element ref="qualification" minOccurs="0"/>
   </xs:sequence>
   <xs:attribute ref="id"/>
</xs:complexType>

Wir können durch Erweiterung aus diesem komplexen Typ einen Datentyp ableiten, der einen Autor als Person mit einer Buchliste beschreibt:

<xs:complexType name="authorType">
   <xs:complexContent>
      <xs:extension base="personType">
         <xs:sequence>
            <xs:element name="book" type="xs:token" minOccurs="1" maxOccurs="unbounded"/>
         </xs:sequence>
      </xs:extension>
   </xs:complexContent>
</xs:complexType>

Wir können durch Einschränkung einen Datentyp ableiten, der eine Buchfigur als Person ohne Sterbedatum, aber mit einer erforderlichen Charakterisierung angibt:

<xs:complexType name="characterType">
   <xs:complexContent>
      <xs:restriction base="personType">
         <xs:sequence>
            <xs:element ref="name"/>
            <xs:element ref="born"/>
            <xs:element ref="qualification"/>
         </xs:sequence>
      </xs:restriction>
   </xs:complexContent>
</xs:complexType>

Der erste Zweck des Attributs block in Elementdefinitionen liegt darin, die Typersetzung durch xsi:type zu steuern, wodurch Ersetzungen in den Instanzdokumenten wie etwa die folgende gesteuert werden (wenn für das Element person der Typ personType definiert worden ist):

<person xsi:type="authorType" id="CMS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <name>
      Charles M. Schulz
   </name>
   <born>
      1922-11-26
   </born>
   <dead>
      2000-02-12
   </dead>
   <book>
      Auf den Hund gekommen
   </book>
</person>
<person xsi:type="characterType" id="Snoopy" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <name>
      Snoopy
   </name>
   <born>
      1950-10-04
   </born>
   <qualification>
      extrovertierter Beagle
   </qualification>
</person>

Die erste Ersetzung verwendet den Typ authorType, der durch Erweiterung von personType abgeleitet ist, und kann blockiert werden, indem ein block-Attribut angegeben wird, das den Wert extension enthält. Die zweite Ersetzung verwendet den Typ characterType, der durch Einschränkung von personType abgeleitet ist, und kann blockiert werden, indem ein block-Attribut angegeben wird, das den Wert restriction enthält. Beide zusammen können blockiert werden, indem man ein block-Attribut mit dem Wert #all angibt.

Dieses Beispiel zeigt, daß sich die Auswirkungen der beiden Arten von Ableitung auf Anwendungen stark unterscheiden. Eine Typersetzung durch Einschränkung hat praktisch keine Auswirkung auf Anwendungen, da das Inhaltsmodell, das zu dem eingeschränkten Typ paßt, auch zu dem ursprünglichen Typ passen muß. Eine Typersetzung durch Erweiterung hingegen läßt Inhaltsmodelle zu, die der ursprüngliche Typ nicht erlaubt (wie die Hinzufügung des Elements book in dem vorangehenden Beispiel), daher ist die Gefahr größer, daß Anwendungen, die diese Hinzufügungen nicht erwarten, nicht mehr laufen. Eine konservative Möglichkeit wäre also, in Ihren Schemas extension in den Vorgabewert für block aufzunehmen.

Nachdem das gesagt ist, haben wir immer noch erst eine Seite des Attributs block gesehen. Es dient noch einem weiteren, unterschiedlichen, aber nicht unabhängigen Zweck und beschränkt auch die Verwendung von Ersetzungsgruppen. Um diesen Verwendungszweck zu veranschaulichen, definieren wir drei verschiedene Elementmitglieder einer Ersetzungsgruppe, deren Kopf person ist. Das dritte Elementmitglied ist einfach ein Synonym für das Element person und hat denselben Typ:

<xs:element name="person" type="personType"/>

<xs:element name="author" type="authorType" substitutionGroup="person"/>

<xs:element name="character" type="characterType" substitutionGroup="person"/>

<xs:element name="human" type="personType" substitutionGroup="person"/>

Nachdem wir diese Ersetzungsgruppe definiert haben, ohne irgend etwas zu blockieren, lassen wir nicht nur block und die Typersetzungen zu, die wir oben gesehen haben, sondern auch Elementersetzungen wie die folgenden:

<author id="CMS">
   <name>
      Charles M. Schulz
   </name>
   <born>
      1922-11-26
   </born>
   <dead>
      2000-02-12
   </dead>
   <book>
      Auf den Hund gekommen
   </book>
</author>
<character id="PP">
   <name>
      Peppermint Patty
   </name>
   <born>
      1966-08-22
   </born>
   <qualification>
      kühn, dreist und draufgängerisch
   </qualification>
</character>
<human id="CMS.">
   <name>
      Charles M. Schulz
   </name>
   <born>
      1922-11-26
   </born>
   <dead>
      2000-02-12
   </dead>
</human>

Die erste Ersetzung verwendet ein Element der Ersetzungsgruppe, dessen Typ durch Erweiterung vom Kopf abgeleitet ist. Sie kann blockiert werden, indem man ein block-Attribut angibt, das den Wert extension enthält. Als zweites folgt eine Ersetzung durch ein Element der Ersetzungsgruppe, dessen Typ durch Einschränkung vom Kopf abgeleitet ist. Sie kann blockiert werden, indem man ein block-Attribut angibt, das den Wert restriction enthält. Diese beiden sind den Substitutionen, die wir als Beispiele für Typsubstitutionen angegeben haben, ähnlich. Der Unterschied besteht darin, daß hier der Elementname verwendet wird, um den Typ zu unterscheiden, und nicht das Attribut xsi:type. Die dritte Ersetzung ist neu, da der Typ derselbe wie der des Kopfes ist, und kann nur blockiert werden, indem man ein block-Attribut angibt, das den Wert substitution enthält. Diesen Wert in ein block-Attribut aufzunehmen blockiert jede Elementersetzung, sagt aber gleichzeitig, daß nicht alle Kombinationen ausgedrückt werden können. Um alles zu blockieren, würde man author so definieren:

<xs:element name="author" type="authorType" block="#all"/>

Ich will bei Ihnen nicht den Eindruck hinterlassen, Sie könnten Typersetzung nicht blockieren, ohne Ersetzungsgruppen zu blockieren. Erwähnenswert ist also, daß Typersetzung auch bei der Definition komplexer Typen blockiert werden kann. Dies wird später im Abschnitt »Komplexe Typen« besprochen.

Finale Elemente

Genau wie block hat auch final Auswirkungen auf Ersetzungsgruppen, diese Konstruktion arbeitet jedoch auf einer anderen Ebene: Sie beschränkt das Schema selbst, nicht jedoch die Instanzdokumente. final kann eine Liste aus den Werten restriction und extension oder den Spezialwert #all annehmen, der Standardwert kann mit Hilfe des Attributs finalDefault von xs:schema vorgegeben werden. Ein Wert substitution ist jedoch nicht notwendig, denn im Gegensatz zu block geht es bei final um Ersetzungsgruppen, und #all kann alle Ersetzungen (und nur diese) blockieren.

Die Auswirkung von final ist radikaler als die von block: Während block die Verwendung von Ersetzungsgruppen blockiert, verbietet final die Verwendung des Elements als Kopf einer Ersetzungsgruppe. Wenn das Element person mit gesetztem Attribut final definiert ist, ist es nicht möglich, es als Kopf einer Ersetzungsgruppe für author, character oder beide gemeinsam zu verwenden.

Abstrakte Elemente

Das letzte Attribut ist abstract, das das Gegenteil zu block darstellt. Es verhindert, daß das Element unmittelbar in einem Instanzdokument verwendet wird. Statt dessen muß es durch eine Ersetzungsgruppe ersetzt werden. Das Element person als abstract zu definieren verbietet seine Verwendung in den Instanzdokumenten. Sie müssen eines der Elemente aus seiner Ersetzungsgruppe (also etwa author, character oder sogar human) verwenden.

Komplexe Typen

Die Attribute für komplexe Typen sind dieselben wie die für Elemente, ihre Bedeutung unterscheidet sich jedoch ein wenig, denn eines der Attribute (block) operiert mit der Ersetzung von Elementen, die den Datentyp verwenden (wie wir es im vorigen Abschnitt gesehen haben), die anderen hingegen (final und abstract) betreffen die Ableitung des komplexen Typs selbst.

Blockieren komplexer Typen

Wenn das block-Attribut bei Definitionen komplexer Typen angewendet wird, sind Typersetzungen bei den mit diesem Typ definierten Elementen immer noch blockiert. Der Unterschied besteht darin, daß sich block in diesem Fall nicht auf Elementersetzungen durch Ersetzungsgruppen, sondern auf Typersetzungen bezieht. Diese block-Attribute kann man sich wie in Serie liegende elektrische Schalter vorstellen, von denen jeder die Ableitung auf seiner eigenen »Leitung« blockieren kann, wie in der folgenden Abbildung gezeigt.

Jeweils für restriction und extension können Ersetzungen zunächst für Element- und Typersetzungen zugleich durch das block-Attribut der Elementdefinition abgeschaltet werden, und zusätzlich können Typersetzungen durch das block-Attribut in der Definition des komplexen Typs blockiert werden. Der Wert substitution im block-Attribut der Elementdefinition wirkt wie ein globaler Schalter für alle Elementersetzungen, einschließlich einer dritten »Leitung«, die Elementersetzungen mit dem gleichen Typ zuläßt und die nicht getrennt blockiert werden kann.

Der im Schema-Element angegebene Standardwert wird auf beiden Ebenen benutzt und kann für Definitionen von Elementen bzw. von komplexen Typen unterschiedlich sein, wenn sie zu unterschiedlichen Schemas gehören und einen unterschiedlichen xs:schema-Ahnen haben. Daß der Standardwert, wenn er im xs:schema-Ahnen definiert ist, auf beide Ebenen angewendet wird, bedeutet, daß er möglicherweise die Ableitung für diese beiden Ebenen blockiert (indem er zwei Schalter »öffnet«). Um einen solchen nicht-leeren Standardwert außer Kraft zu setzen, müssen Sie bei der Definition sowohl von Elementen als auch von komplexen Typen ein block-Attribut angeben.

block-Attribut für Definition von Elementen und komplexen Typen

Abbildung: block-Attribut für die Definition von Elementen und komplexen Typen

Finale komplexe Typen

Das Attribut final steuert bei der Definition komplexer Typen, ob der Typ durch Einschränkung oder Erweiterung abgeleitet werden kann, um neue komplexe Typen zu erzeugen.

Im Gegensatz zum block-Attribut, das mit seinem Gegenstück bei der Elementdefinition verbunden ist, gilt das Attribut final bei der Definition eines komplexen Typs nur für den komplexen Typ selbst. Ähnlich wie das Attribut abstract bei der Elementdefinition wird es auf der Schema-Ebene selbst angewendet und hat keine Auswirkungen auf die Instanzdokumente.

Abstrakte komplexe Typen

Das Attribut abstract operiert bei der Definition komplexer Typen auf den Instanzdokumenten. Wenn ein abstrakter Datentyp verwendet wird, um Elemente zu definieren, muß der Typ in den Instanzdokumenten durch ein xsi:type-Attribut ersetzt werden.

Wir müssen deutlich darauf hinweisen, daß abstract für sich genommen nicht heißt, daß der komplexe Typ nicht in einem Inhaltsmodell verwendet werden kann. Wenn er jedoch verwendet wird, muß er in den Instanzdokumenten durch xsi:type ersetzt werden. Um einen komplexen Typ zu definieren, der nicht in Inhaltsmodellen verwendbar ist, müssen wir sowohl das final- als auch das block-Attribut angeben; dann kann dieser komplexe Typ ausschließlich als Basistyp für Ableitungen verwendet werden.

Einfache Typen

Einfache Typen sind tatsächlich einfacher, was die Kontrolle über ihre Ableitungen angeht, denn sie können höchstens final sein. Ihr final-Attribut kann die Werte list, restriction, union oder den Spezialwert #all annehmen, was für alle drei Werte zugleich steht. Der Standardwert wird durch das Attribut finalDefault des Schema-Elements vorgegeben, der auch für Elemente und komplexe Typen gilt.

Daß einfache Typen nicht abstract oder blockiert sein können, vermeidet mögliche Probleme, wenn sie für die Definition von Attributen verwendet werden, für die diese Begriffe bedeutungslos sind. Falls man sie doch für die Definition von Elementen benötigt, kann man einen komplexen Typ einfachen Inhalts erzeugen, der den einfachen Typ als Basis verwendet. Dieser komplexe Typ kann die Attribute abstract und block aufnehmen.

Auch wenn final das einzige Attribut ist, das Ableitungen von Elementen einfachen Typs steuert und für das Element xs:simpleType (globale Definition) verfügbar ist, kann eine feinere Steuerung durch das Attribut fixed erzielt werden, das für jede der Facetten zur Verfügung steht (wie unter Erzeugung einfacher Datentypen erläutert).

Andere Komponenten und Redefinitionen

Andere Komponenten, beispielsweise Attribute sowie Element- und Attributgruppen, können nicht unmittelbar abgeleitet werden. Attribute können überhaupt nicht abgeleitet werden, Gruppen nur durch Redefinition. Daher gibt es für diese Fälle keine Kontrolle über die Ableitung. Dementsprechend überschreitet auch die Redefinition von Gruppen durch xs:redefine die Möglichkeiten dieser Konstruktion; sie kann ebenfalls überhaupt nicht gesteuert werden. Auch wenn die Empfehlung in dieser Hinsicht unscharf ist, ist es sicherer anzunehmen, daß das final-Attribut der komplexen Typen auch für ihre Redefinition gilt, die wie implizite Ableitungen behandelt werden.

Die Interpretation des block-Attributs ist nicht einheitlich. Die aktelle Ansicht der W3C XML Schema Working Group finden Sie in der Errata-Liste für die Spezifikation.

   

zum Seitenanfang

<< 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