Element-Deklarationen

(Auszug aus "XML in a Nutshell" von Elliotte Rusty Harold & W. Scott Means)

Jedes Element, das in einem gültigen Dokument benutzt wird, muss in der DTD des Dokuments mit einer Element-Deklaration deklariert werden. Element-Deklarationen besitzen diese Grundform:

 

<!ELEMENT name inhaltsspezifizierung>

Als Name des Elements kann jeder zulässige XML-Name verwendet werden. Die Inhaltsspezifizierung gibt an, welche Kinder das Element haben kann oder muss und in welcher Reihenfolge diese erscheinen müssen. Inhaltsspezifizierungen können recht komplex werden. Sie können beispielsweise sagen, dass ein Element drei Kindelemente eines bestimmten Typs haben muss oder zwei Kinder eines Typs, gefolgt von einem weiteren eines zweiten Typs, oder irgendwelche Elemente, die aus sieben verschiedenen Typen ausgewählt werden und die mit Text durchsetzt sind.

#PCDATA

Die einfachste Inhaltsspezifizierung ist eine, die besagt, dass ein Element nur geparste Zeichendaten, jedoch keine Kindelemente eines anderen Typs enthalten darf. In diesem Fall besteht die Inhaltsspezifizierung einfach aus dem Schlüsselwort #PCDATA , das in Klammern gesetzt wird. Zum Beispiel legt diese Deklaration fest, dass ein Element telefonnummer Text, aber keine Elemente enthalten darf:

 

<!ELEMENT telefonnummer (#PCDATA)>

Ein derartiges Element kann auch Zeichenreferenzen und CDATA-Abschnitte (die beim Parsen immer als reiner Text behandelt werden) sowie Kommentare und Verarbeitungsanweisungen (die bei der Validierung eigentlich keine Rolle spielen) enthalten. Es kann außerdem Entity-Referenzen enthalten – aber nur, wenn diese zu einfachem Text ohne irgendwelche Kindelemente aufgelöst werden.

Kindelemente

Eine weitere einfache Inhaltsspezifizierung ist eine, bei der festgelegt wird, dass das Element genau ein Kind eines vorgegebenen Typs haben muss. In diesem Fall besteht die Inhaltsspezifizierung aus dem Namen des Kindelements in Klammern. Diese Deklaration beispielsweise sagt aus, dass ein Element fax genau ein Element telefonnummer enthalten muss:

 

<!ELEMENT fax (telefonnummer)>

Ein fax-Element darf nichts anderes als das Element telefonnummer besitzen, und es darf nicht mehr und nicht weniger als eins davon haben.

Sequenzen

In der Praxis tritt eine Inhaltsspezifizierung, die genau ein Kindelement auflistet, eher selten auf. Die meisten Elemente enthalten entweder geparste Zeichendaten oder (zumindest potenziell) mehrere Kindelemente. Die einfachste Methode, um mehrere Kindelemente zu kennzeichnen, besteht darin, sie mit Kommas zu trennen. Dies wird Sequenz genannt. Eine Sequenz zeigt an, dass die genannten Elemente in der angegebenen Reihenfolge auftreten müssen. Zum Beispiel besagt diese Element-Deklaration, dass ein name-Element genau ein Kindelement vorname enthalten muss, dem genau ein Kindelement nachname folgt:

 

<!ELEMENT name (vorname, nachname)>

Entsprechend dieser Deklaration ist dieses name-Element gültig:

<name>
   <vorname>Madonna</vorname>
   <nachname>Ciconne</nachname>
</name>

Dieses hier dagegen ist nicht gültig, da es die Reihenfolge der beiden Elemente vertauscht:

<name>
   <nachname>Ciconne</nachname>
   <vorname>Madonna</vorname>
</name>

Dieses Element ist ungültig, weil das Element nachname fehlt:

<name>
   <vorname>Madonna</vorname>
</name>

Dieses hier ist ungültig, weil noch ein zusätzliches Element zweiter_vorname auftaucht:

<name>
   <vorname>Madonna</vorname>
   <zweiter_vorname>Louise</zweiter_vorname>
   <nachname>Ciconne</nachname>
</name>

Die Anzahl der Kinder

Wie die obigen Beispiele verdeutlichen, haben nicht alle Instanzen eines bestimmten Elements notwendigerweise genau dieselben Kinder. Sie können einem Elementnamen in einer Inhaltsspezifizierung eines dieser drei Suffixe anhängen, um anzuzeigen, wie oft dieses Element an dieser Stelle erwartet wird:

  • ? Kein oder ein Element ist erlaubt.
  • * Kein oder mehrere Elemente sind erlaubt.
  • + Macht ein oder mehrere Elemente erforderlich.

Diese Deklaration besagt zum Beispiel, dass ein name-Element genau ein Element vorname enthalten muss, ein Element zweiter_vorname und ein Element nachname enthalten kann:

 

<!ELEMENT name (vorname, zweiter_vorname?, nachname?)>

Entsprechend dieser Deklaration sind all diese name-Elemente gültig:

<name>
   <vorname>Madonna</vorname>
   <nachname>Ciconne</nachname>
</name>
<name>
   <vorname>Madonna</vorname>
   <zweiter_vorname>Louise</zweiter_vorname>
   <nachname>Ciconne</nachname>
</name>
<name>
   <vorname>Madonna</vorname>
</name>

Diese hier sind jedoch nicht gültig:

<name>
   <vorname>George</vorname>
   <!-- es ist nur ein zweiter Vorname erlaubt -->
   <zweiter_vorname>Herbert</zweiter_vorname>
   <zweiter_vorname>Walker</zweiter_vorname>
   <nachname>Bush</nachname>
</name>
<name>
   <!-- der Vorname muss vor dem Nachnamen stehen -->
   <nachname>Ciconne</nachname>
   <vorname>Madonna</vorname>
</name>

Sie können mehrfache zweite Vornamen zulassen, indem Sie ein Sternchen hinter zweiter_vorname setzen:

 

<!ELEMENT name (vorname, zweiter_vorname*, nachname?)>

Wollten Sie das Vorhandensein von zweiter_vorname erzwingen, aber weiterhin mehrere zweite Vornamen zulassen, würden Sie stattdessen ein Pluszeichen verwenden:

 

<!ELEMENT name (vorname, zweiter_vorname+, nachname?)>

Auswahl

Manchmal kann eine Instanz eines Elements eine Art von Kind enthalten und eine andere Instanz ein anderes Kind. Das bezeichnet man als Auswahl. Eine Auswahl ist eine Liste mit Elementnamen, die durch senkrechte Striche voneinander getrennt sind. Zum Beispiel besagt diese Deklaration, dass das Element methodResponse entweder ein Kindelement params oder ein Kindelement fault enthält:

 

<!ELEMENT methodResponse (params | fault)>

Es kann jedoch nicht beide Kinder zur gleichen Zeit enthalten. Jedes methodResponse-Element muss entweder das eine oder das andere besitzen.

Auswahlen können auf eine unbegrenzt große Anzahl möglicher Elemente ausgedehnt werden. Zum Beispiel sagt diese Deklaration aus, dass jedes ziffer-Element genau eines der Kindelemente null, eins, zwei, drei, vier, fünf, sechs, sieben, acht oder neun enthalten kann:

<!ELEMENT ziffer (null | eins | zwei | drei | vier | fünf | sechs | sieben | acht | neun)>

Klammern

Für sich allein ist der Nutzen von Auswahlen, Sequenzen und Suffixen ziemlich eingeschränkt. Sie können jedoch beliebig kombiniert werden, um auf diese Weise nahezu jedes denkbare Inhaltsmodell zu beschreiben. Eine Auswahl oder eine Sequenz kann in Klammern eingeschlossen werden. So umschlossen, können der Sequenz oder Auswahl ? , * oder + nachgestellt werden. Darüber hinaus können Sie den eingeklammerten Ausdruck auch in andere Auswahlen oder Sequenzen einschachteln.

Nehmen Sie beispielsweise einmal an, Sie wollen ausdrücken, dass ein kreis-Element ein zentrum-Element und entweder ein radius- oder ein durchmesser-Element enthält, aber nicht beides. Diese Deklaration legt das fest:

 

<!ELEMENT kreis (zentrum, (radius | durchmesser))>

Fahren wir mit einem weiteren Beispiel aus der Geometrie fort. Wie Sie wissen, kann ein Ortspunkt entweder mit kartesischen oder mit Polarkoordinaten beschrieben werden. Jedes Zentrum enthält also entweder ein x und ein y oder ein r und ein θ. Wir deklarieren dies mit zwei kleinen Sequenzen, die jeweils in Klammern stehen und in einer Auswahl kombiniert sind:

 

<!ELEMENT zentrum ((x, y) | (r, θ))>

Nehmen Sie an, es ist Ihnen wirklich egal, ob das Element x vor dem Element y steht oder umgekehrt bzw. ob r vor θ kommt. Sie können die Auswahl so erweitern, dass sie alle vier Möglichkeiten abdeckt:

 

<!ELEMENT zentrum ((x, y) | (y, x) | (r, θ) | (θ, r) )>

Mit dem Anwachsen der Elemente in der Sequenz steigt auch die Anzahl der Permutationen exponentiell an. Daher eignet sich diese Technik wirklich nicht für mehr als zwei oder drei Kindelemente. DTDs können nicht besonders gut ausdrücken, dass Sie n Instanzen von A und m Instanzen von B haben wollen, aber sich wirklich nicht darum kümmern wollen, in welcher Reihenfolge diese auftreten.

Auf eingeklammerte Elemente können auch Suffixe angewendet werden. Nehmen wir einmal an, ein Polygon wird durch einzelne Koordinaten für jeden Eckpunkt definiert, die in einer bestimmten Reihenfolge angegeben werden. Beispielsweise ist das hier ein rechtwinkliges Dreieck:

<polygon>
   <r>0</r> <θ>0</θ>
   <x>0</x> <y>10</y>
   <x>10</x> <y>0</y>
</polygon>

Was wir sagen wollen, ist, dass ein Polygon aus drei oder mehr Paaren von x-y- oder r-θ-Koordinaten zusammengesetzt ist. Einem x folgt immer ein y, und einem r folgt immer ein θ. Durch diese Deklaration wird das erreicht:

<!ELEMENT polygon (((x, y) | (r, θ)), ((x, y) | (r, θ)), ((x, y) | (r, θ))+)>

Das Pluszeichen wirkt auf ((x, y) | (r, θ)).

Um wieder auf das Namensbeispiel zurückzukommen, stellen Sie sich vor, Sie wollen sagen, dass ein Name nur einen Vornamen, nur einen Nachnamen oder einen Vornamen und einen Nachnamen mit einer beliebig großen Anzahl zweiter Vornamen enthalten kann. Folgende Deklaration erzeugt das:

<!ELEMENT name (nachname | (vorname, ( (zweiter_vorname+, nachname) | (nachname?) ))>

Gemischter Inhalt

In erzählenden Dokumenten enthält ein einzelnes Element üblicherweise sowohl Kindelemente als auch nicht-leere Zeichendaten ohne Markup. Denken Sie beispielweise an dieses definition-Element vom Code-Beispiel Ein narrativ organisiertes XML-Dokument der Seite "Elemente, Tags und Zeichendaten" zurück:

<definition>Als <begriff>Turing-Maschine</begriff> bezeichnet man einen abstrakten endlichen Automaten mit unendlichem Speicher, der als äquivalent zu jedem anderen endlichen Automaten mit beliebig großem Speicher angesehen werden kann. Das heißt, was für eine Turing-Maschine gilt, gilt für alle Turing-Maschinen, unabhängig davon, wie sie implementiert wurden.</definition>

Das Element definition enthält einigen nicht-leeren Text und ein Kindelement begriff. Dies wird gemischter Inhalt (mixed content) genannt. Ein Element, das gemischten Inhalt enthält, wird so deklariert:

 

<!ELEMENT definition (#PCDATA | begriff)*>

Diese Deklaration besagt, dass ein Element definition geparste Zeichendaten und begriff-Kindelemente enthalten darf. Es legt weder fest, in welcher Reihenfolge sie auftreten, noch, wie viele Instanzen jeweils vorkommen dürfen. Diese Deklaration erlaubt es einem definition-Element, 1 begriff-Kindelement, 0 begriff-Kindelemente oder 23 begriff-Kindelemente zu besitzen.

Sie können in die Auflistung des gemischten Inhalts eine beliebige Anzahl anderer Kindelemente aufnehmen, allerdings muss #PCDATA immer das erste Kind in der Liste sein. Diese Deklaration beispielsweise sagt aus, dass ein absatz-Element eine beliebige Anzahl der Elemente name, beruf, fußnote, betont und datum in beliebiger Reihenfolge, gemischt mit geparsten Zeichendaten, enthalten darf:

<!ELEMENT absatz (#PCDATA | name | beruf | fußnote | betont | datum)*>

Dies ist die einzige Möglichkeit, mit der angezeigt werden kann, dass ein Element gemischten Inhalt enthält. Sie können zum Beispiel nicht sagen, dass es genau ein Kindelement begriff des Elements definition und geparste Zeichendaten geben kann. Sie können nicht festlegen, dass die geparsten Zeichendaten alle nach dem begriff-Kindelement auftreten müssen. Sie können keine Klammern um eine Deklaration für gemischten Inhalt setzen, um sie zum Bestandteil einer größeren Gruppierung zu machen. Sie können nur festlegen, dass das Element eine beliebige Anzahl beliebiger Elemente aus einer bestimmten Liste in beliebiger Reihenfolge enthält und dass es außerdem undifferenzierte, geparste Zeichendaten enthält.

Leere Elemente

Manche Elemente besitzen überhaupt keinen Inhalt. Sie werden leere Elemente genannt und manchmal mit einem schließenden /> geschrieben:

<bild quelle="bus.jpg" breite="152" höhe="345" alt="Alan Turing steht vor einem Bus" />

Diese Elemente werden in der Inhaltsspezifizierung mit dem Schlüsselwort EMPTY deklariert:

 

<!ELEMENT image EMPTY>

Das besagt lediglich, dass das Element image leer sein muss, aber nicht, dass es mit dem einzelnen Tag für leere Elemente geschrieben werden muss. Bei obiger Deklaration ist auch das ein gültiges image-Element:

<image source="bus.jpg" width="152" height="345" alt="Alan Turing steht vor einem Bus"></image>

Ein leeres Element darf tatsächlich gar nichts enthalten, noch nicht einmal Whitespace! Das hier ist z. B. ein ungültiges image-Element:

<image source="bus.jpg" width="152" height="345" alt="Alan Turing steht vor einem Bus">
</image>

ANY

Sehr lockere DTDs wollen gelegentlich ausdrücken, dass ein Element existiert, ohne irgendwelche Aussagen darüber zu machen, was es enthalten könnte. In diesem Fall können Sie das Schlüsselwort ANY als Inhaltsspezifizierung angeben. Diese Deklaration beispielsweise besagt, dass ein seite-Element beliebigen Inhalt enthalten kann, einschließlich gemischten Inhalt, Kindelemente und sogar andere seite-Elemente:

 

<!ELEMENT seite ANY>

Die Kinder, die dann tatsächlich im Inhalt des Elements seite im Dokument auftauchen, müssen aber immer noch in eigenen Element-Deklarationen deklariert werden. ANY erlaubt es Ihnen nicht, undeklarierte Elemente einzusetzen.

ANY bietet sich manchmal an, wenn Sie gerade beginnen, DTD und Dokumentstruktur zu entwerfen und noch kein klares Bild davon haben, wie die Dinge sich schließlich entwickeln werden. Allerdings ist es kein guter Stil, ANY in fertigen DTDs einzusetzen. Sie werden es höchstens vielleicht dort verwendet finden, wo sich externe DTD-Teilmengen und Entities in unkontrollierbarer Weise verändern. Das kommt aber relativ selten vor. Sie brauchen ANY eigentlich nur dann wirklich, wenn Sie eine DTD für eine Anwendung wie XSLT oder RDF schreiben, die Inhalt aus beliebigen unbekannten XML-Anwendungen einschließen.

  

<< zurück vor >>

 

 

 

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

  


Copyright © 2005 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 in a Nutshell" 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