Sonntag, 12. Februar 2012 |
Das X steht für "eXtensible" und meint erweiterbar. Doch wie die Folge "Wofür steht eigentlich das 'X'?" gezeigt hat, sind die wenigsten XML-Formate erweiterbar, obgleich der
Mechanismus für die Erweiterbarkeit bekannt und einfach anzuwenden ist. Ein
xs:any oder xs:anyAttribute an die richtige Stelle im Schemata gesetzt und schon kann man
sein Format mit dem Prädikat "extensible"
schmücken.
Der Teufel steckt im Detail
Ganz so einfach ist es dann doch nicht. Denn erstens ist eben die
entscheidende Frage: Was ist die richtige Stelle für einen Erweiterungspunkt? Und zweitens bietet sowohl
das Element xs:any als auch das Element xs:anyAttribute verschiedene Konfigurationsmöglichkeiten an, sodass eine weitere Frage
lautet: Welche Erweiterungen erlaube ich?
Das Einfachste zuerst. Also das Element xs:anyAttribute. Doch halt!
Warum möchte man auf einem Element fremde Attribute erlauben?
Hierzu ein
(abschreckendes) Beispiel: Die Spezifikation "XML Inclusions (XInclude)
Version 1.0" beschreibt ein XML-Element include und einen Prozess, wie ein
XInclude-konformer XML-Parser in einem Eingabedokument solche include-Elemente während
des Lesevorgangs durch Inhalte ersetzt, auf die durch die include-Elemente
verwiesen wird. Meistens befinden sich die inkludierten Daten selbst in einer XML-Datei.
Nennen wir diese Datei exemplarisch header.xml. Die Datei enthält neben dem Mission-Statement des Unternehmens ("We are the
best company worldwide.") einen Verweis auf eine Datei logo.gif.
Weil die Entwickler dieses Unternehmens tatsächlich die Besten sind, haben sie
alle Dateien fein säuberlich auf verschiedene Verzeichnisse aufgeteilt. Die Datei logo.gif befindet sich zusammen mit der Datei header.xml im
Verzeichnis templates und im Verzeichnis marketing gibt es die Datei best.xml,
die beschreibt, warum gerade sie die Besten sind. Und weil das Mission-Statement
zusammen mit dem Logo auch überall gleich aussehen soll, inkludiert die Datei best.xml
die Datei header.xml per include-Element:
<xi:include href="../templates/header.xml" />
Selbstverständlich nutzen die Entwickler relative Pfadangaben - man kann ja
nie wissen, welche Umstellung der Admin schon wieder plant. Auch die Datei header.xml verlässt sich daher auf eine relative Pfadangabe zur Datei logo.gif:
<div><img src="logo.gif"/><p><em>We are the best company worldwide.</em></p></div>
Bei der Verarbeitung der Datei best.xml ersetzt der XInclude-konforme XML-Parser das include-Element durch den
eben gezeigten Inhalt der Datei header.xml. Er passt aber keineswegs die
relative Pfadangabe an, denn das würde bedeuten, dass er den Inhalt des XML-Dokuments versteht.
Das soll und kann er aber nicht. Stattdessen vermerkt der XML-Parser im neu
entstandenen XML-Dokument (beziehungsweise im speicherinternen XML-InfoSet-Modell) den ursprünglichen Ort der Daten mithilfe des Attributs xml:base:
<div xml:base="../templates/header.xml"><img src="logo.gif"/><p><em>We are the best company worldwide.</em></p></div>
Dieses Attribut ist nun der Grund dafür, fremde Attribute auf
Elementen zu erlauben. Denn obgleich es dem speziellen XML-Namensraum entstammt,
stellt das Attribut xml:base einen Fremdkörper dar. Und in XML
Schema gilt eben: was nicht ausdrücklich erlaubt ist, ist grundsätzlich verboten.
Ende der Diskussion
Die Lösung ist einfach:
<xs:anyAttribute namespace="http://www.w3.org/XML/1998/namespace" processContents="lax" />
Damit erlauben Sie auf dem jeweiligen Element sämtliche Attribute aus dem
XML-Namensraum - wie etwa auch xml:id zur Vergabe eindeutiger Kennungen an
XML-Elemente. Sie können sogar einen Schritt
weitergehen, indem sie anstelle
des XML-Namensraums den speziellen Wert "##other" für das Attribut namespace
einsetzen und dadurch das Element für Attribute aus einem beliebigen fremden
Namensraum öffnen. Sofern sie eigene globale
Attribute in ihrem Schemata definiert haben und auch diese zulassen möchten,
tragen sie für das namespace-Attribut stattdessen "##any" ein.
Globale Attribute können auf vielfältige Weise genutzt werden. Die Attribute
xml:id und xml:base sind zwei Beispiele. Ein
Kunde von Ihnen könnte die Erweiterungsmöglichkeiten beispielsweise dazu nutzen, Ihre XML-Daten
mit seinen Daten zu verknüpfen - mithilfe eines Attributes: mydb:refid="123".
Nachdem die Fragen nach dem Warum und dem Wie geklärt sind, bleibt noch eines zu klären: Was ist die richtige Stelle? Nun, im Falle der Attribute ist die Antwort einfach: Jedes Element sollte die Möglichkeit haben, sich mit fremden Attributen zu schmücken.
Die Antwort ist nein
Sie werden jetzt eventuell einwenden: "Das ist ja eine Menge Tipparbeit! Geht das
nicht einfacher?" Die Antwort ist: "Nein." Die alternative Antwort, für die, die es
besser wissen, lautet: "Ja, es gibt eine vermeintlich einfachere Lösung. Die
nutzt die Typvererbung in XML Schema und damit ist schon klar: die Lösung ist
keineswegs einfacher." Ihre nächste Frage wird sicherlich lauten: "Und was mache ich bezüglich des Problems
mit XInclude bei Schemata, die nicht von mir selbst stammen?"
Hier gibt es mindestens drei unbefriedigende Antworten: Einen Beschwerdebrief
schreiben. Das Schemata selbst anpassen. Nach einem XML-Parser Ausschau halten,
der es nicht so genau mit der Konformität nimmt. Die XmlReader-Klasse im .NET
Framework 2.0 lässt sich beispielsweise dahingehend konfigurieren.
Sie sehen, die Teufel verstecken sich im Detail. Deshalb widmet sich auch die kommende Folge dem Thema Erweiterbarkeit. Bis dahin, seien Sie offen für Erweiterungen!
Ihr Martin Szugat
Martin Szugat weiß, was Sie jetzt denken: "Dieses XML ist verdammt kompliziert." Und er gibt Ihnen recht. Damit XML verständlich wird, schreibt er regelmäßig über XML im dot.net magazin, bei Naked XML und auf aboutxml.de, hält Vorträge zu XML auf der BASTA und der Webinale und beantwortet die ein oder andere Frage zu XML im Entwickler-Forum.