XML-Know How

Lokale und globale Element-Deklarationen

Wie man am obigen <artikel>-Beispiel gut sieht, ist der Aufbau der XSD hierarchisch prinzipiell mit dem XML-Dokument identisch: wo im XML-Dokument die Elemente stehen, stehen in der XSD die Deklarationen der Elemente. Zur Festlegung von Struktureigenschaften wurden noch einige spezielle XSD-Elemente in der Hierarchie hinzugefügt (z. B. <xs:complexType> und <xs:sequence>). Andere Eigenschaften werden über Attribute zugewiesen (z. B. type-Attribut).

Der hierarchische Aufbau der XSD hat zur Folge, dass Deklarationen von Elementen innerhalb der Deklarationen ihrer Container-Elemente stehen – wie im obigen Beispiel. Solche Deklarationen nennt man lokal.

Sobald man ein Element im Content Model von verschiedenen anderen Elementen verwenden will, wird dieses Vorgehen sehr umständlich, – man müsste dazu ja ein und dasselbe Element in jedem Container-Element neu deklarieren. Um die Mehrfachverwendung von Elementen zu vereinfachen, sieht XSD neben lokalen auch globale Deklarationen vor.

Das heißt: wie in DTDs wird jedes Element für sich deklariert und kann dann in anderen Elementdeklarationen beliebig verwendet werden.

Dazu wird das Element zunächst mittels eines <xs:element> deklariert, das als direktes Kind-Element des <xs:schema>-Elements positioniert ist. Die Wiederverwendung von global deklarierten Elementen bei der Deklaration von anderen Elementen erfolgt über <xs:element>-Elemente, die statt des name-Attributes ein ref-Attribut enthalten. Das ref-Attribut gibt an, welches globale Element an der jeweiligen Stelle wiederverwendet werden soll.

Die folgende Beispiel-XSD ist strukturell identisch mit der obenstehenden, nur dass nun die Elemente <titel>, <teaser> und <inhalt> global deklariert sind und im Element <artikel> verwendet werden:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

<!-- globale Deklarationen von Elementen: -->
<xs:element name="titel" type="xs:string"/>
<xs:element name="teaser" type="xs:string"/>
<xs:element name="inhalt" type="xs:string"/>
...
<xs:element name="artikel">
    <xs:complexType>
       <xs:sequence>

<!-- global deklarierte Elemente werden verwendet: -->
         <xs:element ref="titel" />
         <xs:element ref="teaser" />
         <xs:element ref="inhalt" />
       </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Aus der Möglichkeit lokaler Deklarationen ergibt sich, dass ein Element mehrfach mit gleichem Namen deklariert werden kann – jeweils mit einem anderen Inhaltsmodell.

Ein Beispiel soll das verdeutlichen. Angenommen, eine Wettzeitschrift soll in XML produziert werden. Bei Pferdewetten sollen u. a. die Namen von Eigentümer und Jockey etc. angegeben werden, jeweils in Vor- und Nachname differenziert, während diese Differenzierung beim Namen des Pferdes nicht nötig ist.

Das XML-Dokument könnte man sich so vorstellen:

<eintrag>
  <pferd>
    <name>Speedy X</name>
  </pferd>
  <besitzer>
    <name>
      <nachname>Rich</nachname>
      <vorname>Johnny</vorname>
    </name>
  </besitzer>
  <jockey>
    <name>
      <nachname>Rider</nachname>
      <vorname>Peter</vorname>
    </name>
  </jockey>
</eintrag>

Die entsprechende XSD würde so aussehen:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

<!-- globale Deklaration von <name> mit lokaler Deklaration von <nachname> und <vorname>: -->
<xs:element name="name">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="nachname" type="xs:string"/>
      <xs:element name="vorname" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>  

<!-- Deklaration von <pferd> mit
abweichender lokaler Deklaration von <name>: -->
<xs:element name="pferd">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

<!-- Deklaration von <besitzer> unter
Verwendung der globalen Deklaration von <name>: -->
<xs:element name="besitzer">
  <xs:complexType>
    <xs:sequence>
      <xs:element ref="name"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

<!-- Deklaration von <jockey> unter
Verwendung der globalen Deklaration von <name>: -->
<xs:element name="jockey">
  <xs:complexType>
    <xs:sequence>
      <xs:element ref="name"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

<!-- globale Deklaration von <eintrag>
mit Verwendung der globalen Deklarationen von
<besitzer>, <jockey> und <pferd>: -->
<xs:element name="eintrag">
  <xs:complexType>
    <xs:sequence>
      <xs:element ref="pferd"/>
      <xs:element ref="besitzer"/>
      <xs:element ref="jockey"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

</xs:schema>

Mit einer DTD dagegen könnte <name> nur einmal deklariert werden. Wenn man zwei unterschiedlich aufgebaute Namenselemente bräuchte, müsste man in einer DTD auch zwei verschiedene XML-Elemente deklarieren, z. B. <personenname> und <pferdename>. Oder man definiert die Struktur von <name> so locker, dass beide Füllungen – Text oder Unterelemente – gleichermaßen möglich sind (Mixed Content). Da das aber die Fehlerwahrscheinlichkeit erhöht – man kann dann auch irrtümlich Personennamen eingeben, ohne die Aufteilung in <vorname> und <nachname> zu beachten – geht diese Option am Ziel einer möglichst engen Strukturkontrolle vorbei.

Wenn bei komplexeren Strukturen weitere Namenstypen auftreten, für die in einer DTD je unterschiedlich strukturierte Elemente mit je unterschiedlichen Bezeichnungen angegeben werden müssten, wird es für die Bearbeiter schnell unübersichtlich: sie müssten alleine für Namensangaben ein halbes Dutzend verschiedener XML-Elemente verwenden.

Mit lokalen Deklarationen in XSD entfällt dagegen die Qual der Wahl zwischen den Alternativen »lockere Definition« oder »viele Elementnamen«: man kann den Elementen sowohl einheitliche und »natürliche« Bezeichnungen geben, als auch ihr Inhaltsmodell je nach Kontext anpassen.