Die Grenzen dieser Technik werden sichtbar, sofern das aus mehreren eigenständigen Quellen mit eigenen DTD's zusammengefügte Xml-Dokument auf seine Validität gegen die Vereinigung der DTD's geprüft werden soll. Nun ist etwa das im vorigen Abschnitt verwendete Element 'title' in mehreren DTD's mit diesem Namen deklariert, beim Zusammenführen der DTD's über Parameter-Entities wird deshalb die Fehlermeldung ausgegeben: 'Das Element "title" ist bereits deklariert'. Die Zusammenführung der DTD's scheitert also, sobald zwei verschiedene DTD denselben lokalen Namen deklarieren. Jede DTD müßte sofort den qualified name, zusammengesetzt aus Präfix, Doppelpunkt und lokalem Namen definieren. Das Präfix wird jedoch erst im Xml-Dokument festgelegt, also wäre für jedes Präfix eine Kopie der DTD mit passendem Präfix zu erstellen.
Vielleicht vermuten Leser, daß bei der Deklaration eines Namespace unter Verwendung einer DTD als URI diese geladen und allen Elementen das gewählte Präfix zugewiesen wird. Beispiel:
<?xml version='1.0'?> <!DOCTYPE b:my-root SYSTEM 'http://www.sql-und-xml.de/xml-samples/books-small.dtd'> <b:my-root xmlns:b='http://www.sql-und-xml.de/xml-samples/books-small.dtd'> <b:book> ... </b:book> </b:my-root>Dies würde alle Elemente aus der Datei 'books-small.dtd' beim Laden dieser Datei dynamisch um das Präfix 'b:' ergänzen. Diese Vermutung ist falsch. Hintergrund all dieser Probleme ist, daß die Xml-Recommendation vom Februar 1998 stammt, die Festlegungen zum Namespace (Namespaces in XML - REC-xml-names) dagegen ein Jahr jünger sind. Die Xml-Recommendation, das normative Dokument zu Xml, kennt das Namespace-Konzept nicht.
Zunächst scheint dieses Problem unlösbar zu sein. Denn alle DTD's müßten in Abhängigkeit von den im Xml-Ergebnis-Dokument verwendeten Namespace-Prefixes umgeschrieben werden. Tatsächlich jedoch läßt sich dieses Problem mit Parameter-Entities in Kombination mit einer gemischten, externen und dokumentinternen DTD lösen.
Technischer Hinweis: Mozilla Firebird (0.7) scheint mit den globalen Entities, die im xmlns-Attribut verwendet werden, nicht klarzukommen (Bsp.: <books xmlns="&books.ns-value;">).
Für diese Technik ist keinerlei zusätzliche Programmiersprache notwendig, welche eine als Textdatei existierende DTD-Vorlage laden, alle Elemente mit Prefixes ergänzen und das Ergebnis als neue Datei erzeugen müßte. Dies gelingt ausschließlich mit den Xml-eigenen Werkzeugen. Denn der Ersetzungstext einer Entity kann selbst Deklarationen enthalten und gewisse Werte hierfür - die festgelegten neuen Prefix-Werte - sozusagen 'unmittelbar vor Ausführung' aus der internen Symboltabelle auslesen.
<!-- Entities fuer das Prefix, den Trenner = Doppelpunkt, die Kombination aus beidem, die lokale Wurzel, die nach aussen sichtbare Wurzel und den Namespace --> <!ENTITY % books.prefix ""> <!ENTITY % books.delimiter ""> <!ENTITY % bP "%books.prefix;%books.delimiter;"> <!ENTITY % books.local "books"> <!ENTITY % books.extern "%bP;%books.local;"> <!ENTITY % books.ns-value "http://www.sql-und-xml.de/xml-samples/books.dtd"> <!ENTITY books.ns-value "%books.ns-value;"> <!ENTITY % books.xmlns "xmlns:%books.prefix;"> <!ENTITY % books.xmlns.value "'%books.ns-value;'">Hier werden zunächst diverse Entities definiert. Die beiden ersten können von außerhalb mit spezifischen Werten belegt werden. books.extern wird benötigt, um beim Dazwischenschieben einer weiteren DTD das Wurzelelement dieser DTD zur Verfügung zu stellen. books.ns-value stellt den Namespace-Wert dar. Dies ist sowohl als Parameter-Entity definiert, um später das Attribut mit diesem als Default-Wert zu deklarieren sowie als globale Entity, falls die Namespace-Deklaration in einem übergeordneten Element verwendet werden soll. Die Entity books.xmlns.value setzt den Wert von books.ns-value nochmals in einfache Hochkommata, da ansonsten die Auflösung keinen String ergeben würde.
<!-- Erzeugen aller Elemente / Attribute in einem Entity --> <!ENTITY % books.execute ' <!ELEMENT %books.extern; (%bP;book*)> <!ATTLIST %books.extern; %books.xmlns; CDATA %books.xmlns.value;> <!ELEMENT %bP;book (%bP;title, %bP;author)> <!ELEMENT %bP;title (#PCDATA)> <!ELEMENT %bP;author (#PCDATA)> '> <!-- Ausfuehren der Entity --> %books.execute;Der erste Codeblock definiert eine mehrere Zeilen umfassende Parameter-Entity, die alle Elemente, gegebenenfalls auch Attribute deklariert. Ferner wird zum Wurzelelement das xmlns:Prefix - Attribut hinzugefügt und mit dem Standardwert deklariert. Dies ist notwendig, falls man die DTD eigenständig verwenden möchte. In diesem Fall gehört die Namespace-Deklaration in das Wurzelelement und muß, da die Validität des Xml-Dokumentes geprüft werden soll, zuvor definiert werden. Da in dem gesamten Ausdruck zunächst alle darin enthaltenen Paramter-Entities aufgelöst werden, kann vor jedes Element das aktuelle Präfix hinzugefügt werden, das als 'bP' definiert wurde. Die letzte Zeile führt dieses Entity schließlich aus.
Man kann in DTD's also ähnliche Techniken wie in anderen Programmiersprachen verwenden, bei welchen Befehlsfolgen - hier Entities - zur Laufzeit zusammengefügt und anschließend ausgeführt werden.
Diese DTD, so ungewöhnlich sie auf den ersten Blick aussehen mag, kann wie gewohnt mit einem Xml-Dokument verknüpft werden. Betrachten Sie die Datei books-with-default-namespace.xml:
<?xml version='1.0'?> <!DOCTYPE books SYSTEM "http://www.sql-und-xml.de/xml-samples/books.dtd"> <books xmlns="&books.ns-value;"> <book> <title>Reisen in Frankreich</title> <author>Mustermann, Max</author> </book> </books>Werden die Parameter-Entities nicht im Xml-Dokument redefiniert, so werden die Elemente einfach ohne Präfix genutzt. Es ist jedoch notwendig, den Standardnamespace zu deklarieren, da - zumindest bei der Verwendung des InternetExplorer 6 - ansonsten eine durchaus irreführende Fehlermeldung ausgegeben wird: 'Das Verwenden von Standard-Namespacedeklarationsattributen wird in DTD nicht unterstützt'. Fügt man das xmlns-Attribut explizit ein, entweder per Hand oder mit der vordefinierten globalen Entity, ist das Xml-Dokument valide.
Ebenso ist es möglich, dieselbe DTD mit Präfix zu verwenden. Das gewünschte Präfix wird in der internen DTD definiert, indem der Wert festgelegt wird. Dieser Abschnitt wird vom Parser zuerst ausgeführt. Alle in anschließend geladenen DTD's gefundenen weiteren Deklarationen für dieselbe Entity werden ignoriert, so daß der zuerst festgelegte Wert gültig ist. Dies ist in der Datei books-with-namespace-b.xml genutzt:
<?xml version='1.0'?> <!DOCTYPE b:books SYSTEM "http://www.sql-und-xml.de/xml-samples/books.dtd" [ <!ENTITY % books.prefix "b"> <!ENTITY % books.delimiter ":"> ]> <b:books xmlns:b='&books.ns-value;'> <b:book> <b:title>Urlaub am Mittelmeer</b:title> <b:author>Mustermann, Max</b:author> </b:book> </b:books>Völlig analog zur Datei books.dtd wurde eine Datei events.dtd erstellt, die - mit Ausnahme der Verwendung eines 'value'-Attributes für das Element 'title' ebenso aufgebaut ist. Ein Beispiel für den Default-Namespace liefert die Datei events-with-default-namespace.xml.
Zunächst ist eine neue DTD zu erstellen - genannt events-and-books.dtd:
<!ENTITY % books.dtd SYSTEM "http://www.sql-und-xml.de/xml-samples/books.dtd"> <!ENTITY % events.dtd SYSTEM "http://www.sql-und-xml.de/xml-samples/events.dtd"> %books.dtd; %events.dtd; <!ENTITY % e-a-b.include "INCLUDE"> <![%e-a-b.include;[ <!ELEMENT events-and-books ((%events.extern;)*, (%books.extern;)*)> <!ATTLIST events-and-books %events.xmlns; CDATA #FIXED %events.xmlns.value; %books.xmlns; CDATA #FIXED %books.xmlns.value;> ]]>Diese DTD definiert die beiden bis dato geschriebenen DTD's als Parameter-Entities und lädt diese. Damit stehen die Entities für die Namen der Wurzelelemente (events.extern), die Namespace-Attribute (events.xmlns) und die Attributwerte (events.xmlns.value) zur Verfügung. Also kann das neue Wurzelelement statisch oder - wie hier gezeigt - dynamisch erzeugt werden. Das Xml-Dokument events-and-books.xml basiert auf dieser DTD:
<?xml version='1.0'?> <!DOCTYPE events-and-books SYSTEM "http://www.sql-und-xml.de/xml-samples/events-and-books.dtd" [ <!ENTITY % books.prefix "b"> <!ENTITY % books.delimiter ":"> <!ENTITY % events.prefix "e"> <!ENTITY % events.delimiter ":"> ] > <events-and-books xmlns:b="&books.ns-value;" xmlns:e="&events.ns-value;"> <e:events> <e:event> <e:title e:value='Donnerstag-Runde'/> <e:room>K58</e:room> </e:event> </e:events> <b:books> <b:book> <b:title>Skifahren in den Alpen</b:title> <b:author>Musterfrau, Maria</b:author> </b:book> </b:books> </events-and-books>Wenn man mag, kann man auch in der Datei books-with-namespace-b.xml den DTD-Abschnitt ausklammern, im obigen DOCTYPE-Abschnitt eine globale Entity hinzufügen, die auf dieses externe Xml-Dokument verweist und diese anstelle des unteren <books> - Abschnittes verwenden.
<!ENTITY books SYSTEM "http://www.sql-und-xml.de/xml-samples/books-with-namespace-b.xml">Verwendung:
&books;Dann wird das Xml-Dokument einer anderen Abteilung direkt vom dortigen Server schreibgeschützt eingelesen und mitsamt den anderen, auf anderen DTD's beruhenden Dokumentabschnitten validiert.