So werden XML-Daten codiert

Veröffentlicht: 15. Sep 2000 | Aktualisiert: 17. Jun 2004

Von Chris Lovett

In diesem Artikel wird erklärt, wie die Zeichencodierung funktioniert (insbesondere in XML und dem MSXML-DOM).

Auf dieser Seite

Plattformübergreifende Datenformate Plattformübergreifende Datenformate
XML und Zeichencodierung XML und Zeichencodierung
Zeichensätze und das MSXML-DOM Zeichensätze und das MSXML-DOM
Erstellen von neuen XML-Dokumenten mit MSXML Erstellen von neuen XML-Dokumenten mit MSXML
Schlussfolgerung Schlussfolgerung
Weitere Informationen Weitere Informationen

In der vergangenen Zeit haben mich viele Leute gefragt, wie sie für eine korrekte Übertragung ihrer Daten in XML-Dateien zwischen verschiedenen Plattformen sorgen können. Sie erstellen ein XML-Dokument, geben die Daten ein, setzen einige Tags ein, formatieren die Tags noch bei Bedarf und fügen ggf. die Deklaration

<?xml version="1.0"?>

ein, um als gutes Beispiel voran zu gehen. Als Nächstes versuchen sie, das Dokument zu laden, erhalten jedoch einen unerwarteten Fehler vom Microsoft® XML Parser (MSXML), in dem auf irreguläre Verhalten in den XML-Daten hingewiesen wird. Für den neuen XML-Autoren kann dies frustrierend sein. Kann denn nichts einfach mal funktionieren?

Anscheinend nicht. Die Ursache dieses MSXML-Fehlers kann z.B. sein, dass auf der Plattform, die die Daten annimmt, diese Daten anders gespeichert werden als auf der Plattform, von der sie gesendet wurden. Das führt zu Problemen bei der Zeichencodierung.

Plattformübergreifende Datenformate

Die Erstellung plattformübergreifender Technologien, die die Datenfreigabe über mehrere Plattformen ermöglichen, ist eine Aufgabe, an der die Computersoftware- und -hardwareindustrie schon so lange arbeitet wie es gelungen ist, zwei Computer miteinander zu verbinden. Seit diesen frühen Tagen sind die Dinge jedoch wesentlich komplizierter geworden – allein aufgrund der Vielzahl der unterschiedlichen Computertypen, der Verbindungsarten und der Daten, die Sie zwischen diesen gemeinsam nutzen möchten.

Nach jahrzehntelanger Forschung auf dem Gebiet der plattformübergreifenden Programmiertechnologien ist die einzig echte (und wohl die am längsten währendste) Lösung, die platttformübergreifend wirkt, die Implementierung von Standarddatenformaten. Der Erfolg des Internets begründet sich tatsächlich auf diesen Datenformaten. Die wichtigsten Formate, die heutzutage zwischen Webservern und Webbrowsern ausgetauscht werden, sind der HTTP-Header und die HTML-Seiten, beides standardmäßige Textformate.

In den folgenden Abschnitten gehe ich auf die Zeichencodierung und Standardzeichensätze, Unicode, den HTML Content-Type-Header, die HTML Content-Type-Metatags und Zeichenentitäten ein. Wenn Sie mit diesen Konzepten bereits vertraut sind, können Sie bei den Tipps und Tricks fortfahren, die der Programmierer für das Codieren von XML-Daten für das XML-Dokumentenobjektmodell (DOM) benötigt. Weitere Informationen finden Sie unter XML und Zeichencodierung.

Eine Lektion in Zeichencodierung

Standardtextformate werden mit Standardzeichensätzen gebaut. Sie erinnern sich vielleicht, dass in allen Computern Text im Zahlenformat gespeichert wird. In unterschiedlichen Systemen kann der gleiche Text jedoch auch mit anderen Zahlen gespeichert werden. In der folgenden Tabelle sehen Sie, wie ein Bytebereich gespeichert wird – zunächst auf einem Standardcomputer, auf dem Microsoft Windows® mit der Standardcodepage 1252 ausgeführt wird, und dann auf einem Standard-Apple® Macintosh®, der die lateinische Macintosh Codepage verwendet.

Byte

Windows

Macintosh

140

Œ

å

229

å

Â

231

ç

Á

232

è

Ë

233

é

È

Beispiel: Ihre Oma aus Schweden bestellt ein Buch bei http://www.barnesandnoble.com/, weiß aber nicht, dass Zeichen auf ihrem Macintosh Computer anders gespeichert werden als auf dem neuen Windows 2000-Webserver, auf dem www.barnesandnoble.com läuft. Während sie ihre schwedische Heimatadresse in das Feld für die Lieferadresse des Internetbestellformulars eingibt, ist sie der Meinung, dass das Zeichen å (Bytewert 140 auf dem Macintosh) richtig im Internet übertragen wird. Sie bedenkt dabei aber (verständlicherweise) nicht, dass ihre Nachricht von Computern empfangen und verarbeitet wird, die den Bytewert 140 als Buchstaben Œ übersetzen.

Unicode

Das Unicode-Konsortium hat einmal entschieden, dass es Sinn machen würde, wenn es eine universelle Codepage (die zwei Byte anstatt einem pro Zeichen verwendet) geben würde, die alle Sprachen der Welt abdeckt. So wäre das Zuordnungsproblem zwischen unterschiedlichen Codepages ein für alle Mal behoben.

Wenn Unicode also plattformübergreifende Zeichencodierungsprobleme löst, warum wurde es dann nicht zum einzigen Standard? Zunächst einmal bedeutet die Umstellung auf Unicode in manchen Fällen eine Verdoppelung der Größe all Ihrer Dateien – in einer netzwerkorientierten Welt nicht der Idealfall. Einige Leute bevorzugen es daher weiterhin, die älteren Single-Byte-Zeichensätze wie ISO-8859-1 bis ISO-8859-15, Shift-JIS, EUC-KR usw. zu verwenden.

Dann gibt es auch immer noch viele Systeme, die überhaupt nicht auf Unicode basieren. Das heißt, dass in einem Netzwerk einige der Bytewerte, die den Unicode-Zeichensatz bilden, zu schweren Problemen auf älteren Systemen führen können. Es wurden also Unicode Transformation Formats definiert (die sog. UTF-Formate); sie verwenden Bitverschiebungstechniken, um die Unicode-Zeichen als Bytewerte zu codieren, die auf diesen älteren Systemen "transparent" (bzw. datenflusssicher) sind.

Das beliebteste Format dieser Zeichencodierungen ist UTF-8. UTF-8 nimmt die ersten 127 Zeichen des Unicode-Standards (die rein zufällig die wichtigsten lateinischen Buchstaben, A-Z, a-z und 0-9 sowie einige Interpunktionszeichen darstellen) und ordnet diese direkt Single-Byte-Werten zu. UTF-8 wendet dann einen Bitverschiebungsmechanismus an, indem es mit dem höchsten Bit der Byte die restlichen Unicode-Zeichen codiert. Das alles hat zur Folge, dass der kleine schwedische Buchstabe å (0xE5) in den folgenden Double-Byte-Kauderwelsch Ã¥ (0xC3 0xA5) konvertiert wird. Sofern Sie also keine Bitverschiebung im Kopf ausführen können, sind UTF-8-codierte Daten nicht vom Menschen lesbar.

Content-Type-Header

Da die älteren Single-Byte-Zeichensätze noch verwendet werden, ist das Problem der Datenübertragung noch nicht gelöst, solange wir nicht zusätzlich angeben, in welchem aktuellen Zeichensatz sich die Daten befinden. Unter Berücksichtigung dieses Problems haben die Internet-E-Mail- und HTTP-Protokollgruppen ein Standardverfahren definiert, um den Zeichensatz im Nachrichtenheader (Content-Type-Eigenschaft) zu spezifizieren. Die Eigenschaft legt einen Zeichensatz aus der Liste der registrierten Zeichensatznamen fest, die von der Internet Assigned Numbers Authority (IANA) definiert wird. Ein typischer HTTP-Header kann z.B. den folgenden Text enthalten:

HTTP/1.1 200 OK 
Content-Length: 15327 
Content-Type: text/html; charset:ISO-8859-1; 
Server: Microsoft-IIS/5.0 
Content-Location: https://www.microsoft.com/Default.htm 
Date: Wed, 08 Dec 1999 00:55:26 GMT 
Last-Modified: Mon, 06 Dec 1999 22:56:30 GMT 

Dieser Header gibt der Anwendung das an, was nach dem Header im ISO-8859-1-Zeichensatz folgt.

Content-Type-Metatags

Die Content-Type-Eigenschaft ist optional; in einigen Anwendungen werden die Informationen im HTTP-Header abgeschnitten, und es wird nur die eigentliche HTML weitergegeben. Zur Abhilfe haben die HTML-Standard-Gruppen ein optionales Metatag als Möglichkeit definiert, den Zeichensatz im HTML-Dokument selbst festzulegen. Dadurch beschreibt sich der Zeichensatz des HTML-Dokuments selbst.

<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1"> 

In diesem Fall deklariert der Zeichensatz ISO-8859-1, dass in dieser besonderen HTML-Seite der Bytewert 229 für den Buchstaben å steht. Diese Seite ist nun auf allen Systemen völlig eindeutig, und Fehlinterpretationen von Daten sind ausgeschlossen. Leider bleibt aber das Risiko von Fehlern, da das Metatag optional ist.

Zeichenentitäten

Nicht alle Systeme unterstützen jeden registrierten Zeichensatz. Ich glaube z.B. nicht, dass viele Plattformen tatsächlich den IBM-Großrechner-Zeichensatz (EBCDIC) unterstützen. Windows NT kann dies, jedoch nicht viele andere Betriebssysteme – das ist sehr wahrscheinlich auch der Grund, warum die Homepage von IBM (http://www.ibm.com) ASCII-Text produziert.

Als Notfallplan lässt HTML die Codierung von einzelnen Zeichen in der Seite zu, indem es ihre exakten Unicode-Zeichenwerte festlegt. Diese Zeichenentitäten werden dann unabhängig vom Zeichensatz analysiert, und ihre Unicode-Werte können zweifelsfrei bestimmt werden. Die Syntax dafür lautet "&#229;" oder "&#xE5;".

 

XML und Zeichencodierung

XML "lieh" sich diese Ideen von HTML und prägte sie dann noch stärker aus. Dabei definierte XML einen vollständig zweifelsfreien Algorithmus, um die verwendete Zeichensatzcodierung zu bestimmen. In XML definiert ein optionales Codierungsattribut in der XML-Deklaration die Zeichencodierung. Mit dem folgenden Algorithmus werden die Standardcodierungen bestimmt:

Wenn die Datei mit einer Unicode-Bytereihenfolgemarkierung beginnt ([0xFF 0xFE] bzw. [0xFE 0xFF]), wird angenommen, dass das Dokument in UTF-16 codiert ist. Wenn nicht, ist es UTF-8-codiert.

Die folgenden XML-Dokumente sind korrekte und gleichwertige Beispiele:

Zeichensatz oder Codierung

HTTP-Header

XML-Dokument

ISO-8859-1

Content-Type: text/xml; charset:ISO-8859-1;

<test>å</test>

UTF-8

Content-Type: text/xml;

<test>Ã¥</test>

ISO-8859-1

Content-Type: text/xml;

<?xml version="1.0" encoding="ISO-8859-1"?><test>å</test>

UTF-8 (verwendet Zeichenentitäten)

Content-Type: text/xml;

<test>&#229;</test>

UTF-16 (Unicode mit Bytereihenfolgemarkierung)

Content-Type: text/xml;

ff fe 3c 00 74 00 65 00 73 00 74 00 3e 00 e5 00 ..<.t.e.s.t.>...3c 00 2f 00 74 00 65 00 73 00 74 00 3e 00 0d 00 <./.t.e.s.t.>...0a 00

 

Zeichensätze und das MSXML-DOM

Wir wissen jetzt also, auf welch vielfältige Weise Zeichen codiert werden können. Lassen Sie uns nun betrachten, wie XML-Dokumente in das MSXML-DOM (DOM steht für Dokumentobjektmodell) geladen werden und welche Fehler Sie u.U. erhalten können, wenn zweideutig codierte Zeichen angetroffen werden. Die beiden wichtigsten Methoden für das Laden von XML DOM-Dokumenten sind LoadXML und Load.

Die LoadXML-Methode benötigt immer einen Unicode-BSTR, der ausschließlich in UCS-2 oder UTF-16 codiert sein darf. Wenn Sie etwas anderes als einen gültigen Unicode-BSTR an LoadXML weiterleiten, schlägt der Ladevorgang fehl.

Die Load-Method kann die folgenden Argumente als VARIANT-Datentypen akzeptieren:

Wert

Beschreibung

URL

Wenn der VARIANT ein BSTR ist, wird er als URL interpretiert.

VT_ARRAY | VT_UI1

Der VARIANT kann auch ein SAFEARRAY sein, das die rawcodierten Byte enthält.

IUnknown

Wenn der VARIANT eine IUnknown-Schnittstelle ist, ruft das DOM-Dokument QueryInterface für IStream,IPersistStream und IPersistStreamInit auf.

Die Load-Methode implementiert den folgenden Algorithmus für die Bestimmung der Zeichencodierung oder des Zeichensatzes des XML-Dokuments:

  • Wenn der Content-Type-HTTP-Header einen Zeichensatz definiert, setzt dieser Zeichensatz alle anderen Einstellungen im eigentlichen XML-Dokument außer Kraft. Dies trifft offensichtlich nicht auf SAFEARRAY- und IStream-Mechanismen zu, da es hier keinen HTTP-Header gibt.

  • Wenn es eine Double-Byte-Unicode-Bytereihenfolgemarkierung gibt, nimmt diese an, dass die Codierung in UTF-16 erfolgt. Sie kann sowohl Big-Endian- als auch Little-Endian-Byteordnungen bearbeiten.

  • Wenn es eine Vier-Byte-Unicode-Bytereihenfolgemarkierung (0xFF 0xFE 0xFF 0xFE) gibt, nimmt diese an, dass die Codierung in UTF-32 erfolgt. Sie kann sowohl Big-Endian- als auch Little-Endian-Byteordnungen bearbeiten.

  • Wenn nichts von dem zutrifft, wird als Codierung UTF-8 angenommen, sofern keine XML-Deklaration mit einem Codierungsattribut gefunden wird, das einen anderen Zeichensatz (z.B. ISO-8859-1, Windows-1252, Shift-JIS usw.) vorschreibt.

Es gibt zwei vom XML-DOM zurückgegebene Fehler, an denen Sie sehen können, dass es Probleme bei der Codierung gibt. Der erste Fehler gibt i.d.R. an, dass ein Zeichen im Dokument nicht mit der Codierung des XML-Dokuments übereinstimmt:

An invalid character was found in text content.

Das ParseError-Objekt teilt Ihnen genau mit, wo in einer bestimmten Zeile sich dieses "vagabundierende" Zeichen befindet, damit Sie das Problem beheben können.

Der zweite Fehle rgibt an, dass Sie mit einer Unicode-Bytereihenfolgemarkierung begonnen haben (oder die LoadXML-Methode aufgerufen haben) und dass dann in einem Codierungsattribut etwas anderes als Double-Byte-Codierung (z.B. UTF-8 oder Windows-1250) festgelegt wurde:

Switch from current encoding to specified encoding not supported.

Alternativ dazu haben Sie u.U. die Load-Methode aufgerufen und dann mit einer Single-Byte-Codierung (ohne Bytereihenfolgemarkierung) begonnen, dann aber an irgendeiner Stelle ein Codierungsattribut angegeben, dass eine Double- oder Vier-Byte-Codierung (z.B. UTF-16 oder UCS-4) vorschreibt.

Ergo können Sie nicht zwischen einem Multibyte-Zeichensatz wie UTF-8, Shift-JIS oder Windows-1250 und Unicode-Zeichencodierungen wie UTF-16, UCS-2 oder UCS-4, die das Codierungsattribut in einer XML-Deklaration verwenden, umschalten, da die Deklaration selbst die gleiche Anzahl an Byte pro Zeichen wie das übrige Dokument haben muss.

Schließlich bietet die IXMLHttpRequest-Schnittstelle die folgenden Methoden für den Zugriff auf downgeloadete Daten:

Methode

Beschreibung

ResponseXML

Stellt den Antwortentitäts-Textkörper so dar, wie er vom MSXML DOM-Parser analysiert wurde (verwendet dieselben Regeln wie die Load-Methode).

ResponseText

Stellt den Antwortentitäts-Textkörper als Zeichenfolge dar. Diese Methode decodiert den empfangenen Nachrichtentext aus UTF-8 blind. Dies ist ein bekanntes Problem, das in der nächsten MSXML-Webversion behoben sein sollte.

ResponseBody

Stellt den Antwortentitäts-Textkörper als Array von nichtsignierten Byte dar.

ResponseStream

Stellt den Antwortentitäts-Textkörper als IStream-Schnittstelle dar.

 

Erstellen von neuen XML-Dokumenten mit MSXML

Sowie das XML-Dokument geladen ist, können Sie dieses XML-Dokument über das DOM bearbeiten, ohne sich Sorgen um etwaige Codierungsprobleme machen zu müssen, da das Dokument im Unicode-Format gespeichert wird. Alle XML DOM-Schnittstellen basieren auf COM-BSTRs, d.h. Double-Byte-Zeichenfolgen (Unicode). Das heißt, Sie können ein MSXML DOM-Dokument völlig neu im Speicher anlegen, das alle möglichen Unicode-Zeichen enthält, und alle Komponenten sind in der Lage, dieses DOM im Speicher gemeinsam zu nutzen. Irrtümer in Bezug auf die Bedeutung der Unicode-Zeichenwerte sind somit ausgeschlossen. Wenn Sie dieses Dokument speichern, codiert MSXML allerdings alle Daten standardmäßig in UTF-8. Angenommen, Sie programmieren Folgendes:

var xmldoc = new ActiveXObject("Microsoft.XMLDOM") 
var e = xmldoc.createElement("test"); 
e.text = "å"; 
xmldoc.appendChild(e); 
xmldoc.save("foo.xml"); 

Die resultierende UTF-8-codierte Datei sieht folgendermaßen aus:

<test>Ã¥</test>

Anmerkung Das vorherige Beispiel funktioniert nur, wenn Sie den Code außerhalb der Browserumgebung ausführen. Durch den Aufruf der Save-Methode noch im Browser erhalten Sie nicht dieselben Resultate, da es Sicherheitsbeschränkungen gibt.

Auch wenn es merkwürdig aussieht – es ist korrekt! Im folgenden Test wird die UTF-8-codierte Datei hochgeladen, und UTF-8 wird in den Unicode-Zeichenwert 229 zurückdecodiert. Der Test als XML-Code:

var xmldoc = new ActiveXObject("Microsoft.XMLDOM") 
xmldoc.load("foo.xml"); 
if (xmldoc.documentElement.text.charCodeAt(0) == 229) 
{ 
    WScript.echo("Juchhe! - es funktioniert!!!"); 
} 

Wenn Sie die Codierung ändern möchten, die die XML DOM-Save-Methode verwendet, müssen Sie eine XML-Deklaration mit einem Codierungsattribut am Anfang des Dokuments erstellen. Das geht so:

var pi = xmldoc.createProcessingInstruction("xml",  
                        " version='1.0' encoding='ISO-8859-1'"); 
xmldoc.appendChild(pi);

Wenn Sie die Save-Methode aufrufen, erhalten Sie im Anschluss eine ISO-8859-1-codierte Datei (wie folgt):

<?xml version="1.0" encoding="ISO-8859-1"?> 
<test>å</test>

Lassen Sie sich jetzt nicht von der XML-Eigenschaft beirren. Die XML-Eigenschaft gibt eine Unicode-Zeichenfolge zurück. Wenn Sie die XML-Eigenschaft des DOMDocument-Objekts aufrufen, nachdem Sie die ISO-8859-1-Codierungsdeklaration erstellt haben, erhalten Sie als Rückgabe die folgende Unicode-Zeichenfolge:

<?xml version="1.0"?> 
<test>å</test> 

Sie werden bemerken, dass die ISO-8859-1-Codierungsdeklaration nicht mehr da ist. Das ist normal. Der Grund dafür ist, dass Sie nun die Hand dafür frei haben, die LoadXML-Methode mit dieser Zeichenfolge aufzurufen. Es funktioniert. Wäre die Deklaration noch da, würde LoadXML mit dem folgenden Fehler fehlschlagen:

Switch from current encoding to specified encoding not supported.

 

Schlussfolgerung

Hoffentlich konnten wir Ihnen mit diesem Artikel ein wenig die Funktionsweise der Zeichencodierung näher bringen, besonders in XML und im MSXML-DOM. Wenn Sie die Zeichensatzcodierung einmal verstanden haben, ist sie sehr einfach. XML ist einfach hervorragend, da es in dieser Hinsicht keine Zweideutigkeiten aufkommen lässt. Das MSXML-DOM hat einige Eigenarten, die Sie berücksichtigen müssen. Dennoch bleibt es ein leistungsstarkes Tool, mit dem Sie jede beliebige XML-Codierung sowohl lesen als auch schreiben können.

 

Weitere Informationen