fjh: Namenräume und Validierung: Nachtrag

Beitrag lesen

Hallo zusammen,

eigentlich gehört das Folgende hier zu einem Thread, der nun entweder im Archiv gelandet oder im Nirvana verschwunden ist.

Dabei ging es um die Probleme, die das Konzept der XML-Namensräume und das Konzept der Validierbarkeit von XML-Dokumenten mit sich bringen. Es gab ein wenig Konfusion, was die Möglichkeit angeht, Elementtypen mit Namensraum-Präfix (html:h1) in einer DTD deklarieren zu können. Dass es geht, ist klar, aber irgendwie haben mir die Details dann keine Ruhe mehr gelassen, zumal am nächsten Tag ein Kollege ein ähnliches Problem hatte. Ich habe nochmal rumprobiert, nachgelesen und gebe es "kurz" zum Besten, falls es mal jemand gebrauchen kann (ich vote dann auch für mich selbst, damit's ins Archiv wandert ;-):

XML-Namensräume dienen dazu, Namenskonflikte und Mehrdeutigkeiten in XML-Dokumenten zu vermeiden, die Elemente aus zwei (oder mehr) DTDs enthalten. Will ich zum Beispiel einem XML-Dokument mit der Adresse einer Geschäftsstelle, die Rechner der Geschäftsstelle hinzufügen, kann es zu einem Namenskonflikt bezüglich der Verwendung des Elements <adresse> kommen (Rechneradresse!). Um diesen zu vermeiden, deklariere ich zwei unterschiedliche Namensräume für die Elemente aus den verschiedenen DTDs:

<geschäftsstelle
       xmlns:adr="http://www.myServer.de/adresse"
       xmlns:rech="http://www.myServer.de/rechner">
  <name>Superladen 22</name>
  adr:adresse
    adr:strasseWiener Str. 23</adr:strasse>
    adr:ortBerlin</adr:ort>
    adr:landGermany</adr:land>
  </adr:adresse>
  edv:rechner
    edv:typFileserver</edv:typ>
    edv:bezLena 2</edv:bez>
    edv:adresse123.54.51.8</edv:adresse>
  </edv:rechner>
</geschäftsstelle>

Soweit so gut, aber wie sieht es nun mit der Gültigkeit dieses Dokuments aus. Nehmen wir an, ich hatte vorher ein gültiges Dokument ohne das <rechner>-Element und ohne Namensraum-Präfixe. Ich füge nun die Namenraum-Deklarationen hinzu.

Zunächst einmal verweisen die beiden Namensraum-Deklarationen nicht auf dahinterliegende Schemata oder DTDs. Sie dienen lediglich als eindeutige Identifizierungs-IDs. Ich könnte nun versuchen meine rechner-DTD über eine zweite Dokumenttyp-Deklaration (<!DOCTYPE ...>) einzubinden. Aber dies ist in XML nicht zulässig. Möglich wäre (wie der untere Thread gezeigt hat) aber eine Einbindung der zweiten DTD über ein externes Parameter-Entity innerhalb meiner ersten DTD.

Aber auch dies reicht nicht, selbst wenn alle hinzukommenden Elementtypen deklariert sind. Grund: Elemente tragen ja nun Namensraum-Präfixe und müssen deswegen auch MIT diesen deklariert werden.

Also:

<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ELEMENT foo (#PCDATA)>
]>
adr:foo
  Geschreibsel
</adr:foo>

ist kein gültiges Dokument.

Deklariere ich nun den Elementtyp mit Namensraumpräfix:

<?xml version="1.0"?>
<!DOCTYPE adr:foo [
  <!ELEMENT adr:foo (#PCDATA)>
]>
adr:foo
  Geschreibsel
</adr:foo>

habe ich zwar ein gültiges Dokument, aber der Namensraum ist nicht deklariert (Gültigkeit hat nichts zu tun mit korrektem Gebrauch von Namensräumen!). OK, füge ich eine Namensraum-Deklaration hinzu:

<?xml version="1.0"?>
<!DOCTYPE adr:foo [
  <!ELEMENT adr:foo (#PCDATA)>
]>
<adr:foo xmlns:adr="http://www.myServer.de/adresse">
  Geschreibsel
</adr:foo>

Tja, nun ist aber mein Dokument nicht mehr gültig, weil das Attribut xmlns:adr nicht deklariert ist. (Wobei dies Parser-abhängig ist: Der msxml3-Parser im IE beschwert sich korrekterweise über die fehlende Attributlisten-Deklaration, während Xerces 1.4 nichts auszusetzen hat). Also muss die ganze Geschichte so aussehen:

<?xml version="1.0"?>
<!DOCTYPE adr:foo [
  <!ELEMENT adr:foo (#PCDATA)>
    <!ATTLIST adr:foo
          xmlns:adr CDATA #FIXED "http://www.myServer.de/adresse">
]>
adr:fooGeschreibsel</adr:foo>

Die Deklaration des Attributs als FIXED funktioniert nicht in allen Parsern (hier ist es z.B. umgekehrt: der IE meckert trotz allem [fälschlicherweise], dass der Namensraum adr nicht deklariert sei, mit Xerces 1.4 funktioniert es aber tadellos). Wer auf Nummer sicher gehen will, muss deswegen wohl immer den Namensraum auch noch im Wurzelelement deklarieren.

Die Übertragung auf das Rechner-Adressen-Beispiel ist klar...

Zu beachten ist dabei, dass die Namensräume nicht in der DTD anwendbar sind. D.h.für den Parser sind die Namensraum-Präfixe in der DTD nicht Stellvertreter des Namensraum-URI, sondern lediglich ein Teil des Element- oder Attributnamen. Mit anderen Worten: eine DTD, in der Elemente aus zwei Namensräumen Verwendung finden, weiss nix davon, dass sie es hier mit zwei Namensräumen zu tun hat. (Thomas: Vielleicht meintest du das ?) Folgendes Dokument ist also gültig:

<?xml version="1.0"?>
<!DOCTYPE adr:foo [
  <!ELEMENT adr:foo (edv:foo)>
    <!ATTLIST adr:foo
              xmlns:adr CDATA #FIXED "http://www.myServer.de/">
  <!ELEMENT edv:foo (#PCDATA)>
    <!ATTLIST edv:foo
              xmlns:edv CDATA #FIXED "http://www.myServer.de/">
]>
adr:foo
  edv:fooGeschreibsel</edv:foo>
</adr:foo>

Würden innerhalb einer DTD die Attributlisten-Deklarationen als Namensraum-Deklarationen aufgefasst und dann die qualifizierten Namen der Elementtypen beim Parsen aufgelöst zu expandierten Namen ("http://www.myServer.de:foo"), dann wären beide gleich und das Dokument ungültig, da laut http://www.w3.org/TR/REC-xml#elemdecls ein Elementtyp nicht mehr als einmal deklariert werden darf. Dem ist aber nicht so.

Gruß
Franz