XML-Workshop Teil 2: XML-Vokabulare Marke Eigenbau
Artikel erschienen in Swiss IT Magazine 2001/13
Im ersten Teil unseres XML-Workshops, der in der letzten Ausgabe von InfoWeek (12/2001) erschienen ist, haben wir uns angesehen, wie Daten mit Markup beschrieben werden können, wie XML-Dokumente aufgebaut sind und welche Syntaxregeln bei XML eingehalten werden müssen. Dieser zweite Teil zeigt nun, wie man das Datenmodell eines XML-Dokuments kreiert. Solche XML-Modelle werden in sogenannten Schemata beschrieben, die man sich als eine Art Bauplan vorstellen muss, in dem definiert ist, welche Elemente und Attribute im Dokument vorkommen dürfen (Vokabular), wie diese strukturiert sind und welche Datentypen innerhalb von Elementen und Attributen gültig sind. Benötigt werden Schemata zur Schaffung von einheitlichen Datenschnittstellen, so dass jede Anwendung, die XML-Dokumente anhand eines eigenen XML-Modells erstellen oder verarbeiten muss, weiss, nach welchem Muster diese aufgebaut sind. So können sich mehrere Partner auf ein gemeinsames Format einigen und damit
sicherstellen, dass sich ein XML-Dokument an die nötigen Vorgaben hält.
Entspricht ein XML-Dokument punkto Strukturierung und Syntax allen in der XML-Spezifikation definierten Richtlinien, so spricht man von einem wohlgeformten Dokument. Diesen Status eines XML-Dokuments haben wir bereits im letzten Teil ausführlich behandelt. Die Wohlgeformtheit sagt allerdings nichts darüber aus, ob in einem Dokument beispielsweise das richtige Vokabular verwendet wird. Aus diesem Grund gibt es für XML-Daten noch einen weiteren Status, die sogenannte Gültigkeit. Spricht man von gültigen XML-Dokumenten, so meint man also, dass diese einem bestimmten Vokabular entsprechen, gemäss dem vorgegebenen Modell korrekt verschachtelt sind und dass die eingebetteten Informationen den vorbestimmten Datentypen entsprechen. Die Gültigkeit wird wie die Wohlgeformtheit von einem Parser überprüft, der dazu das entsprechende Schema in den Validierungsvorgang miteinbezieht.
Neben der bereits erwähnten Normierung von Datenschnittstellen hat die Verwendung von Schemata als angenehmen Nebeneffekt auch den Vorteil, dass man an zentraler Stelle eine einheitliche Dokumentation über das verwendete XML-Dokumentmodell hat, das von jedem XML-Entwickler verstanden wird.
Auf dem Markt gibt es bereits ein ganze Palette von Schema-Spezifikationen. Neben dem weitverbreiteten DTD-Standard (Document Type Definition) kann man für die Definition von eigenen Markup-Sprachen derzeit auch auf die Spezifikation RDF (Reduced Data Framework), XML Data und DCD (Document Content Description) zurückgreifen. Bei RDF handelt es sich um eine umfangreiche Modellierungssprache für die Definition von Abhängigkeiten zwischen Objekten. Sie ist durch ihre Mächtigkeit aber für die meisten XML-Anwendungen zu komplex. XML Data und DCD wurden von Microsoft resp. IBM ins Leben gerufen. Es sind zwei eher simple Spezifikationen, die unter anderem dazu geschaffen wurden, die Wartezeit auf den vielversprechenden Schema-Standard zu verkürzen.
DTD ist bislang die einzig breit anerkannte Sprache für die Definition eigener XML-Markups. Praktisch alle vom W3C kreierten Vokabulare wie XHTML, SVG oder WML beruhen auf einer DTD. Ausser der weiten Verbreitung bringen DTDs nur wenige Vorteile. So verfügen DTDs über eine eigentümliche, schwer lesbare Syntax, unterstützen keine echten Datentypen und sind in Sachen Funktionsumfang sehr eingeschränkt. Aus diesem Grund hat das W3C vor einiger Zeit mit der Entwicklung von XML Schema begonnen, das das Beste aus RDF, XML Data und DCD in einer einfach anzuwendenden Spezifikation kombinieren soll. XML Schema, das noch vor diesem Sommer endgültig ratifiziert werden dürfte, bietet gegenüber den DTDs derart viele Vorteile, dass kaum jemand an dessen breiten Akzeptanz zweifelt. Viele Hersteller haben bereits Support für XML Schema versprochen. Und auch das W3C will künftige Standards, wie etwa XHTML 2.0, auf Basis von XML Schema formulieren.
Im Klartext bietet XML Schema gegenüber DTD die folgenden Vorteile:
einfacher lern- und lesbar, da XML als Syntax genutzt wird
breites Angebot an Datentypen, ähnlich wie es in heutigen Datenbanken zu finden ist
unterstützt Namespaces und Vererbung
kann per Document Object Model (DOM) dynamisch manipuliert werden
erlaubt das Aufsplitten von Schemata in mehre Sub-Schemata, die sich beliebig kombinieren lassen.
Da man derzeit noch kaum um DTD herumkommt und XML Schema die Zukunft gehört, zeigen wir in diesem Workshop die Schema-Definition anhand beider Varianten auf.
Wie bereits erwähnt, basieren Document Type Definitions nicht auf XML, sondern auf einem eigenen Syntax. Dies obwohl die DTD mit in die XML-1.0-Spezifikation integriert wurden.
Eine DTD beginnt immer mit dem speziellen Element , das den Start und die Wurzel einer DTD definiert. Man kann wahlweise auf interne (Inline DTDs) oder externe DTDs zurückgreifen:
Direkt hinter dem Kommando muss das Wurzelelement, also dasjenige Element, mit dem der Rumpf unseres XML-Dokuments beginnt, angegeben werden. In unserem Beispiel wäre dies das Element lieferung. Bei der Inline-DTD folgen anschliessend die Deklarationen innerhalb von eckigen Klammern. Bei externen DTDs kann mit den Optionen PUBLIC oder SYSTEM angegeben werden, ob es sich um eine öffentlich verfügbare, standardisierte oder um eine eigene hausinterne DTD handelt. Direkt danach folgt der Pfad oder die URL, die dem Parser mitteilt, wo er die DTD auffinden kann.
Grundsätzlich können in DTDs drei XML-Bausteine definiert werden: Elemente, Attribute und Entities. Jedes Element und jedes Attribut, das in einem XML-Dokument vorhanden sein kann, muss in der DTD zwingend deklariert werden.
• Elemente: Elemente werden mit dem Kommando definiert, dem der entsprechende Elementname (buch) angefügt wird. Zusätzlich lässt sich in Klammern der verwendete Datentyp angeben. Die in DTDs verfügbaren Datentypen finden Sie im nebenstehenden Kasten. Für leere Elemente kann der Schlüsselbegriff EMPTY verwendet werden.
• Attribute: Für Attribute steht der Befehl bereit. In der Attributdeklaration wird zunächst angegeben, zu welchem Element das Attribut gehört (buch), gefolgt vom Namen des Attributs (isbn) und dem Datentyp (id). Mit der Option #REQUIRED kann erzwungen werden, dass das Attribut vorhanden sein muss. Mit #FIXED kann einem Attribut ein Vorgabewert zugewiesen werden. Ist das entsprechende Attribut in einem Element vorhanden, so muss es zwingend über diesen Wert verfügen.
#IMPLIED bewirkt, dass das Attribut optional ist, also bei Bedarf auch weggelassen werden kann.
• Entities: Bei den Entities handelt es sich um Platzhalter, auf die, wenn sie einmal in der DTD deklariert wurden, im XML-Dokument beliebig referenziert werden kann. In unserem Beispiel haben wir die Entity mwst definiert und ihr den Wert 7,6 zugewiesen. Im XML-Dokument kann nun durch Angabe von &mwst der Wert der Entity beim Parsing an der entsprechenden Stelle eingefügt werden:
Ändert sich nun eines Tages der Mehrwertsteuersatz, so braucht man diesen nur einmal an zentraler Stelle in der DTD anzupassen. Auch Pfadangaben und URLs sind ideale Kandidaten für Entities, da sich Pfade oft ändern können und auch nicht selten derart lang sind, dass sie das XML-Dokument unübersichtlich machen.
Verschachtelungen lassen sich in der DTD durch die Verwendung von Klammern beschreiben. So wird mit der folgenden Zeile...
Natürlich müssen die Elemente vorname, nachname und alter ebenfalls in der entsprechenden DTD deklariert werden.
Für die Beschreibung der Reihenfolge und Kardinalität bietet DTD vier verschiedene Operatoren an:
• (+) Pluszeichen: Das Element muss ein oder mehrmals vorhanden sein.
• (*) Asterisk: Das Element ist optional, darf also nie, einmal oder beliebig oft vorkommen.
• (?) Fragezeichen: Das Element darf kein- oder maximal einmal verwendet werden.
• (|) Vertikaler Strich: Erlaubt die Vorgabe einer Liste von Elementen, die vorhanden sein dürfen.
Kombiniert man diese Operatoren, so können recht komplexe Konstrukte gebildet werden:
Diese Deklaration bestimmt, dass innerhalb des Vaterelements fruchtkorb das Element kirsche zwingend vorhanden sein muss, apfel und birne in beliebiger Reihenfolge auf kirsche folgen dürfen und dass am Schluss das Element melone im Maximum einmal vorhanden sein darf. Folgendes Konstrukt wäre gemäss der oben gezeigten DTD-Deklaration beispielsweise korrekt formuliert:
Nachdem wir nun betrachtet haben, wie man Schemata mit Hilfe von Documtent Type Definitions kreiert, schauen wir uns nun an, wie man mit XML Schema weitaus elegantere und mächtigere XML-Modelle entwerfen kann.
XML Schemas sind selber XML-Dokumente, mit dem Unterschied, dass sie auf die Dateie-Extension .xsd statt .xml enden. Ein XML Schema beginnt mit der Standard-XML-Deklaration ( gefolgt von der Definition des XML-Schema-Namensraums, der allen Schema-Elementen und Attributen das Präfix xsd zuordnet (Dokumentaufbau und Namespaces siehe Teil 1 dieses XML-Workshops in InfoWeek 12/2001 oder auf der InfoWeek-Website im Archiv-Bereich). Nachfolgend die elementare Grundstruktur eines XML-Schema-Dokuments:
Die Schema-Integration ist in drei Teile aufgegliedert. Mit xmlns:mitarbeiter wird zunächst der Namensraum definiert, der durch das Schema beschrieben wird. In unserem Fall ist das der Namensraum mitarbeiter, wie anhand des Präfixes zu erkennen ist. Dann wird der Namensraum xsi definiert, der für die Schema-Integration benötigt wird. Und schliesslich folgt mit xsi:schemaLocation die Pfadangabe, in unserem Fall eine URL, wo das Schema zu finden ist.
Falls keine Namensräume verwendet werden, wird das Schema auf dieselbe Weise mit dem Attribut xsi:noNamespaceSchemaLocation aufgerufen. In diesem Fall würde auch die Namespace-Deklaration, erster Teil des Beispiels, weggelassen.
In XML Schema wird zwischen einfachen und komplexen Datentypen unterschieden. Elemente und Attribute, die nur einfachen Content (Text, Zahlen, URIs etc.) beinhalten dürfen, werden als Simple Types bezeichnet. Unter Complex Types fallen alle Elemente, die andere Elemente oder Attribute beinhalten.
Wie wir bereits gesehen haben, gibt es in den DTDs keine echte Datentypen. XML Schema hingegen bietet weit mehr Möglichkeiten, den Content von XML-Dokumenten zu kontrollieren, und erlaubt damit einen reibungsloseren Datenaustausch zwischen Systemen.
Bei XML Schema gehört bereits eine ganze Auswahl von Datentypen, ähnlich wie sie in Datenbanken anzutreffen sind, zur Grundausstattung. Dazu zählen beispielsweise die Typen Integer, String, Date, Time, Float, URI oder Boolean. Diese werden in XML Schema wie folgt angewendet:
Diese Elemente werden mit den zwei einfachen Datentypen string für Text und integer für eine Integerzahl definiert. Alternativ zu den vorbereiteten Typen, können auch eigene Simple Types kreiert werden, mit denen sich die Kontrolle über die Daten noch finetunen lässt. Diese werden immer von einem bestehenden Datentyp abgeleitet:
In diesem Beispiel wird der eigene Datentyp postleitzahl definiert, der von string abgeleitet werden soll. In XML Schema heisst das Element für solche Ableitungen restriction, was zu Deutsch nichts anderes als Einschränkung bedeutet. Genau nach diesem Muster funktionieren die Ableitungen in XML Schema denn auch: Man nimmt bestehende Datentypen und grenzt deren Gültigkeit weiter ein. In unserem Beispiel tun wir das mit dem Element pattern, mit dem man einem Datentyp ein bestimmtes Zeichenmuster vorgeben kann, das eingehalten werden muss. In unserem Fall definieren wir mit dem Ausdruck \d{4,5}, dass der Datentyp postleitzahl mindestens 4 bis maximal 5 Ziffern beinhalten darf. Hinter den Ausdrücken für die Patterns verbirgt sich übrigens die Regex-Syntax, die von der Programmiersprache Perl übernommen wurde.
Neben pattern gibt es noch weitere XSD-Elemente, mit der sich Datentypen einschränken lassen.
• Aufzählung: Mit xsd:enumeration kann eine Liste von Werten definiert werden, die als Elementinhalt in Frage kommt. Für ein Element wetter könnte man folgende Einschränkung definieren:
• Bereiche: Mit den Attributen minInclusive und maxInclusive lässt sich ein Gültigkeitsbereich spezifizieren:
• Vorgeben von Inhalt: Mit den Attributen fixed und default kann einem Element ein bestimmter Inhalt vorgegeben werden. Bei fixed darf das Element nur den angegebenen Wert annehmen, bei default wird automatisch der hier definierte Wert eingefügt, wenn das Element leer ist.