Die document type definition zur Validierung eigener Xml-Dokumente

Vorbemerkung: Um die folgenden Beispiele praktisch anwenden zu können, benötigen Sie einen validierenden Parser. Falls Sie den Internet Explorer Version 6 nutzen oder sich bei einem InternetExplorer ab Version 5 die MSXML3 von Microsoft installiert haben, können Sie den Online-Xml-Trainer verwenden.

Soll das Xml-Dokument nicht nur wohlgeformt sein, sondern soll zusätzlich festgelegt werden, welche Elemente, Attribute und welche Schachtelungen erlaubt sind, so muß ein eigener Xml-Dokumenttyp beschrieben werden. Jeder dieser Dokumenttypen ist durch eine genau festgelegte Menge an Element-Typen und zugeordneten Attribut-Typen charakterisiert. Bei der Definition von jedem Element-Typ wird zusätzlich festgelegt, welche Typen von Unterelementen bzw. ob Text als Content dieses Elementtyps erlaubt ist. Eine solche Definition eines Dokument-Typs, eine eigene document type definition (DTD) deklariert also, welche zusätzlichen Einschränkungen ein bereits wohlgeformtes Xml-Dokument erfüllen muß, damit es zusätzlich als 'Dokument dieses Dokumenttyps' betrachtet werden darf. Eine DTD kann ferner Entity-Deklarationen enthalten. Diese kann man sich vorstellen als Funktionen oder Makros, die einen Wert, eine Zeichenfolge oder den Inhalt eines Dokuments zurückliefern und dessen Verwendung gestatten. Von Entities gibt es zwei Typen: Globale Entities können überall dort verwendet werden, wo gemischter Content, also #PCDATA zulässig ist. Parameter-Entities dienen als Makros innerhalb der externen DTD.

Damit muß einem Dokument eine DTD zugeordnet werden, dies ist auf vier verschiedene Arten möglich. Allen Arten gemeinsam ist, daß das Xml-Dokument einen Abschnitt enthält, der minimal wie folgt aussieht:
<!DOCTYPE QName

	... hier folgen weitere Festlegungen

>

<QName>

	... hier folgt der Dokumentinhalt

</QName>
QName ist sowohl der Name der DTD als auch der Name des Wurzel-Elements dieses Xml-Dokumentes. Bei QName handelt es sich um einen qualified Name, der entweder keinen Doppelpunkt enthält oder - im Sinne eines Namespaces - in Präfix und local part zerfällt, verbunden durch den Doppelpunkt.

Zuordnungsmöglichkeiten zwischen einem Dokument und seiner DTD

1. Interne DTD

Eine DTD kann zunächst innerhalb eines Xml-Dokuments erstellt werden. Dann gilt diese DTD jedoch auch nur für dieses Dokument, so daß für jedes Xml-Dokument eine eigene DTD erstellt werden muß. Um zu lernen, wie Element- und Attributtypen definiert werden, genügt diese Version.
Beispiel:
<?xml version='1.0'?>
<!DOCTYPE small-sample
	[
	<!ELEMENT small-sample EMPTY>
]>

<small-sample></small-sample>
Die Definitionen werden innerhalb des obigen Rahmens notiert und zusätzlich in eckige Klammern eingeschlossen.

2. Verweis auf eine externe DTD in einer Datei

Die meistens verwendete Version für selbsterstellte große DTD's, auf die viele Dokumente aufbauen, besteht in der Erstellung einer externen DTD, die per Verweis eingebunden wird. Die externe DTD ist eine übliche Textdatei im Ansi- oder Unicode-Format.
<?xml version='1.0'?>
<!DOCTYPE firma-max-mustermann SYSTEM
	"http://www.sql-und-xml.de/xml-samples/firma-max-mustermann.dtd" >

<firma-max-mustermann>

	<!-- ... weitere Unterelemente und Content -->

</firma-max-mustermann>

Das Schlüsselwort SYSTEM fordert einen anschließenden Verweis auf eine URI, dies kann eine lokale oder eine per http referenzierte externe Datei sein. Diese enthält jene Angaben, welche bei der internen Definition in eckigen Klammern stehen. Die eingebundene externe DTD firma-max-mustermann.dtd definiert lediglich zwei Entities für das nächste Beispiel sowie das Wurzelelement.

3. Verweis auf eine externe DTD und lokale Definitionen

Eine erweiterte Technik besteht darin, einerseits eine externe DTD zu referenzieren und andererseits lokale Definitionen, etwa globale Entities, zu ergänzen, die speziell in diesem Xml-Dokument benötigt werden.
<?xml version='1.0'?>
<!DOCTYPE firma-max-mustermann SYSTEM
	"http://www.sql-und-xml.de/xml-samples/firma-max-mustermann.dtd"
	[
	<!ENTITY my-signatur "Max Mustermann" >

]>

<firma-max-mustermann>

	&gruss;

	<!-- ... weitere Unterelemente und Content -->

	&my-signatur;

</firma-max-mustermann>
Die Definition der Elemente wird aus der externen DTD firma-max-mustermann.dtd geholt. Diese enthält bereits zwei Entities. Die zweite Entity wird lokal redefiniert, so daß der lokal festgelegte Wert tatsächlich im Dokument sichtbar wird. Die externe Entity enthält das Copyright-Zeichen, in der lokalen Definition fehlt dieses, letztere wird angezeigt.
Man kann also Entities doppelt definieren, in der externen DTD sind sie bereits gültig. Im lokalen Dokument definiert man sie erneut und weist ihnen damit einen anderen Wert zu, dieser überschreibt den zunächst zugewiesenen Wert.

4. Verwendung eines PUBLIC - Identifiers

Die vierte Möglichkeit besteht darin, einen PUBLIC-Identifier, einen veröffentlichten und dem Parser bekannten Dokumenttyp zu verwenden.
<?xml version='1.0'?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
	"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" >

<html>

	<!-- hier folgt ein XHTML1.1 - konformes Xml-Dokument -->

</html>
Bei einigen weltweit bekannten und genutzten DTD existiert für diese eine eindeutige Bezeichnung, ein öffentlicher Identifier. Hier wäre es nicht sinnvoll, direkt die DTD anzugeben, so daß der Parser bei jedem Laden eines Html-Dokuments die gesamte DTD verarbeitet. Stattdessen wird dem Parser intern ein Modul mitgegeben, welches die DTD in einer bereits verarbeiteten Version enthalten dürfte. So muß nur noch geprüft werden, ob das aktuelle Dokument diese DTD erfüllt.
Ein solcher PUBLIC-Identifier wird direkt hinter dem Schlüsselwort PUBLIC notiert. Anschließend kann eine DTD direkt angegeben werden, dies ist jedoch nicht zwingend. Bei einem Identifier ist die Zeichenfolge strikt zu beachten.

Conditional Sections: Verwenden von INCLUDE und IGNORE

Die beiden Schlüsselwörter INCLUDE und IGNORE erlauben eine Art von Direktiven, wie man sie von Programmiersprachen her kennt. Allerdings können beide Schlüsselwörter nur in externen DTD's genutzt werden. Die direkte Verwendung erinnert an CDATA-Sections:
<![INCLUDE[

	<!-- Anweisungen, die einzuschliessen sind -->

]]>
IGNORE wird ebenso verwendet, schließt jedoch die festgelegten Anweisungen aus. Interessant wird diese Technik, falls man sie mit Entities kombiniert:
<!ENTITY experimental 'INCLUDE'>
<!ENTITY final 'IGNORE'>

<![%experimental;[
	<!ELEMENT program (internal-comments*, title, code, abstract)>
]]>

<![%final;[
	<!ELEMENT program (title, code, abstract)>
]]>
Entities können mit diesen Schlüsselwörtern belegt werden, so daß erst zur Analysezeit der INCLUDE-Block festgelegt wird. Im ersten Fall wird das Element 'program' mit zusätzlichen, nicht zur Veröffentlichung bestimmten Kommentaren ergänzt, im zweiten Fall hat das Element 'program' keine entsprechenden Unterelemente. Einfaches Vertauschen von 'experimental' und 'final' bei der Entity-Deklaration erzeugt einen veränderten Dokumenttyp und erzwingt das Entfernern aller Kommentare.
Da Entities im Xml-Dokument redefiniert werden können und diese die in der externen DTD deklarierten Werte überschreiben, läßt sich damit auch eine Veränderung der Namespace-Deklaration leicht erzeugen.

Nutzen einer DTD

Der Aufwand für die Erstellung einer DTD kann rasch einen größeren Umfang annehmen. Im folgenden finden Sie einige Hinweise, wann man eine DTD verwenden sollte bzw. wann sich der Aufwand für die Erstellung einer DTD nicht lohnt.

Mögliche Gründe für eine DTD

Situationen, in welchen sich die Mühe für eine DTD nicht lohnt


© 2003-2018 Jürgen Auer, Berlin.