Rubrik: Dateisystem · XML | VB-Versionen: VB2005, VB2008, VB2010 | 23.05.11 |
XML mit StringWriter und der gewünschten Kodierung Haben Sie sich auch schon einmal darüber geärgert, dass wenn Sie ein XML-File mittels eines StringBuilders erstellen das Encoding auf UTF-16 steht? | ||
Autor: Marcus Jacob | Bewertung: | Views: 11.561 |
www.jacob-software-development.de | System: Win2k, WinXP, Win7, Win8, Win10, Win11 | kein Beispielprojekt |
Ein bisschen Grundlagen:
Das Standard-Encoding eines Strings in .NET ist UTF-16. Es gibt durchaus einige Diskussionen zu diesem Thema. Ich will nicht in die Details gehen, abgesehen von einigen seltenen Gelegenheiten, Fehler und Merkwürdigkeiten, sind
Zeichenfolgen in. NET wirklich intern UTF-16 kodiert. (siehe MSDN)
Immer wenn Sie Strings benutzen und die Notwendigkeit besteht, diese in einen Stream zu wandeln oder ein ByteArray in einen String, müssen Sie ein Encoding angeben.
Die Standardkodierung für XML ist UTF-8 oder UTF-16. Jeder XML-Parser prüft hierzu die ersten Bytes auf das Vorhandensein einer Byte-Order-Mark (BOM). Diese muss benutzt werden, um die korrekte Kodierung des Dokuments zu erhalten. Wenn das Dokument mit 0xFF 0xFF 0xFE oder 0xFE beginnt dann ist die Kodierung UTF-16, wenn es mit 0xEF 0xBB 0xBF beginnt dann UTF-8. Ist keine BOM vorhanden muss das erste Zeichen ein "<"-Zeichen sein, welches jeweils unterschiedlich kodiert ist. Anhand dessen wird die Kodierung erkannt.
Nach der Logik des XML-Standards, muss die Codierung in der XML-Deklaration mit der Kodierung des Dokuments übereinstimmen. Die Zeichenfolgen werden in .NET als UTF-16 gespeichert, so dass die logische und einzige Wahl, welche man hat (hätte), folgende Deklaration ist:
<? xml version = "1.0" encoding = "UTF-16"?>
Folgender Code demonstriert dies:
Private Function BuildXML() As String Dim document As New XmlDocument() Dim builder As New StringBuilder() Dim inputXML As String = "<root><Element1>Text1</Element1><Element2>Text2</Element2></root>" document.Load(New StringReader(inputXml)) Using writer As New XmlTextWriter(New StringWriter(builder)) writer.Formatting = Formatting.Indented document.Save(writer) End Using Return builder.ToString() End Function
Beim Ausführen erhalten wir folgendes:
<?xml version="1.0" encoding="utf-16"?> <root> <Element1>Text1</Element1> <Element2>Text2</Element2> </root>
Wie wir es uns schon gedacht haben: Encoding = UTF-16.
Wie kriegen wir jetzt hier eine UTF-8-Kodierung hin? Der "Übeltäter" ist der StringWriter. Er hat eine feste Kodierung implementiert. (Wer möchte kann dies mittels Reflector nachvollziehen.)
Und hier schreiben wir unseren eigenen erweiterten StringWriter, dem wir die Kodierung mitgeben können welche wir möchten. Dazu folgende Klasse:
Imports System.Text Imports System.io Public Class ExtStringWriter Inherits StringWriter Private _Encoding As Encoding Public Sub New(ByVal encoding As Encoding) MyBase.New() _Encoding = encoding End Sub Public Sub New(ByVal formatProvider As IFormatProvider, _ ByVal encoding As Encoding) MyBase.New(formatProvider) _Encoding = encoding End Sub Public Sub New(ByVal sb As StringBuilder, _ ByVal encoding As Encoding) MyBase.New(sb) _Encoding = encoding End Sub Public Sub New(ByVal sb As StringBuilder, _ ByVal formatProvider As IFormatProvider, ByVal encoding As Encoding) MyBase.New(sb, formatProvider) _Encoding = encoding End Sub Public Overrides ReadOnly Property Encoding() As Encoding Get Return _Encoding End Get End Property End Class
Nun haben wir die Möglichkeit das Encoding selbst zu bestimmen. Mit dem erweiterten StringWriter sieht unser Beispiel von oben nun wie folgt aus:
Private Function BuildXML() As String Dim document As New XmlDocument() Dim builder As New StringBuilder() Dim inputXML As String = "<root><Element1>Text1</Element1><Element2>Text2</Element2></root>" document.Load(New StringReader(inputXml)) Using writer As New XmlTextWriter(New ExtStringWriter(builder, Encoding.UTF8)) writer.Formatting = Formatting.Indented document.Save(writer) End Using Return builder.ToString() End Function
Und hier die Ausgabe:
<?xml version="1.0" encoding="utf-8"?> <root> <Element1>Text1</Element1> <Element2>Text2</Element2> </root>
Also: Geht doch!