2009-10-14 4 views
81

Ich bin derzeit auf der Suche nach einer einfachen Möglichkeit zum Serialisieren von Objekten (in C# 3).Verwenden von StringWriter für XML-Serialisierung

gegoogelt ich einige Beispiele und kam mit so etwas wie oben:

MemoryStream memoryStream = new MemoryStream (); 
XmlSerializer xs = new XmlSerializer (typeof (MyObject)); 
XmlTextWriter xmlTextWriter = new XmlTextWriter (memoryStream, Encoding.UTF8); 
xs.Serialize (xmlTextWriter, myObject); 
string result = Encoding.UTF8.GetString(memoryStream .ToArray()); 

Nach der Lektüre dieses question Ich habe mich gefragt, warum mit String nicht? Es scheint viel einfacher.

XmlSerializer ser = new XmlSerializer(typeof(MyObject)); 
StringWriter writer = new StringWriter(); 
ser.Serialize(writer, myObject); 
serializedValue = writer.ToString(); 

Ein weiteres Problem war, dass das erste Beispiel XML erzeugt konnte ich nicht nur schreiben in eine XML-Spalte von SQL Server 2005 DB.

Die erste Frage ist: Gibt es einen Grund, warum ich StringWriter nicht verwenden sollte, um ein Objekt zu serialisieren, wenn ich es danach als String brauche? Ich habe nie ein Ergebnis mit StringWriter beim googlen gefunden.

Die zweite ist natürlich: Wenn Sie es nicht mit StringWriter tun sollten (aus welchen Gründen auch immer), was wäre ein guter und korrekter Weg?


Zusatz:

Wie bereits von beiden Antworten erwähnt wurde, werde ich weiter in die XML gehe Problem DB.

Wenn in die Datenbank zu schreiben habe ich die folgende Ausnahme:

System.Data.SqlClient.SqlException: XML-Analyse: Zeile 1, Zeichen 38, nicht in der Lage, die Codierung zu wechseln

Bei String

<?xml version="1.0" encoding="utf-8"?><test/> 

nahm ich die Zeichenfolge des XmlTextWriter erstellt und nur als xML th setzen ehe. Dieser hat nicht funktioniert (weder beim manuellen Einfügen in die DB).

Danach versuchte ich manuell einfügen (nur schreiben INSERT INTO ...) mit encoding = "utf-16", die auch fehlgeschlagen. Entfernen der Codierung total funktioniert dann. Nach diesem Ergebnis bin ich zurück zum StringWriter-Code und voila - es hat funktioniert.

Problem: Ich verstehe nicht wirklich warum.

bei Christian Hayter: Mit diesen Tests bin ich nicht sicher, ob ich utf-16 verwenden muss, um in die DB zu schreiben. Würde die Codierung nicht auf UTF-16 (im XML-Tag) eingestellt?

+1

Ich bin Persönliche Erfahrung: SQL Server akzeptiert nur UTF-16, und wenn Sie etwas anderes übergeben, sind Sie dem SQL Server-XML-Parser und seinen Versuchen, die Daten zu konvertieren, ausgeliefert, anstatt nach einer Möglichkeit zu suchen, sie zu täuschen Ich übergebe es einfach UTF-16 direkt, was immer funktioniert. –

+0

Wie schreibt man dies in die Datenbank? Übergeben Sie es eine Zeichenfolge oder ein Array von Bytes oder Schreiben in einen Stream? Wenn es eine der letzteren ist Bei zwei Formularen müssen Sie sicherstellen, dass Ihre deklarierte Codierung mit der tatsächlichen Codierung Ihrer Binärdaten übereinstimmt: –

+0

Puh. Der manuelle Versuch, den ich als Abfrage im MS SQL Management Studio gemacht habe. Die "codierten" Versuche wurden in einen String geschrieben, der dann an einen O/R-Mapper übergeben wurde, der als String schreibt (soweit ich folgen konnte). Tatsächlich übergebe ich es die Zeichenfolge, die in den beiden Beispielen in meiner Frage erstellt wurde. – StampedeXV

Antwort

121

Bei der Serialisierung eines XML-Dokuments in eine .NET-Zeichenfolge muss die Codierung auf UTF-16 festgelegt werden. Strings werden intern als UTF-16 gespeichert, daher ist dies die einzige Codierung, die Sinn macht. Wenn Sie Daten in einer anderen Codierung speichern möchten, verwenden Sie stattdessen ein Byte-Array.

SQL Server funktioniert nach einem ähnlichen Prinzip; Jede Zeichenfolge, die an eine xml-Spalte übergeben wird, muss als UTF-16 codiert sein. SQL Server lehnt alle Zeichenfolgen ab, bei denen die XML-Deklaration UTF-16 nicht angibt. Wenn die XML-Deklaration nicht vorhanden ist, erfordert der XML-Standard, dass standardmäßig UTF-8 verwendet wird. Daher lehnt SQL Server dies ebenfalls ab.

In diesem Sinne, hier sind einige Hilfsmethoden für die Konvertierung.

public static string Serialize<T>(T value) { 

    if(value == null) { 
     return null; 
    } 

    XmlSerializer serializer = new XmlSerializer(typeof(T)); 

    XmlWriterSettings settings = new XmlWriterSettings() 
    { 
     Encoding = new UnicodeEncoding(false, false), // no BOM in a .NET string 
     Indent = false, 
     OmitXmlDeclaration = false 
    }; 

    using(StringWriter textWriter = new StringWriter()) { 
     using(XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings)) { 
      serializer.Serialize(xmlWriter, value); 
     } 
     return textWriter.ToString(); 
    } 
} 

public static T Deserialize<T>(string xml) { 

    if(string.IsNullOrEmpty(xml)) { 
     return default(T); 
    } 

    XmlSerializer serializer = new XmlSerializer(typeof(T)); 

    XmlReaderSettings settings = new XmlReaderSettings(); 
    // No settings need modifying here 

    using(StringReader textReader = new StringReader(xml)) { 
     using(XmlReader xmlReader = XmlReader.Create(textReader, settings)) { 
      return (T) serializer.Deserialize(xmlReader); 
     } 
    } 
} 
+0

Siehe Zusatzfrage. Ich verstehe meine Testergebnisse nicht, es widerspricht Ihrer Aussage, dass die DB UTF-16 immer will/braucht. – StampedeXV

+6

Sie müssen * nicht * als UTF-16 kodieren - aber Sie müssen sicherstellen, dass die verwendete Kodierung dem entspricht, was der 'StringWriter' erwartet. Siehe meine Antwort. Das interne Speicherformat spielt hier keine Rolle. –

+0

ok das verstehe ich. In meinem neuen Beispiel: Nachdem die Codierung vollständig weggelassen wurde, hat die DB selbst entschieden, welche Kodierung verwendet wurde - deshalb funktionierte sie. Verstehe ich es jetzt richtig? – StampedeXV

167

Ein Problem mit StringWriter ist, dass standardmäßig it doesn't let you set the encoding which it advertises - so können Sie am Ende mit einem XML-Dokument Werbung für seine Codierung als UTF-16, was bedeutet, dass Sie es als UTF-16 verschlüsseln müssen, wenn Sie es in eine Datei schreiben.Ich habe eine kleine Klasse mit, dass, obwohl zu helfen:

public sealed class StringWriterWithEncoding : StringWriter 
{ 
    public override Encoding Encoding { get; } 

    public StringWriterWithEncoding (Encoding encoding) 
    { 
     Encoding = encoding; 
    }  
} 

Oder wenn Sie brauchen nur UTF-8 (die brauchen alles, was ich oft):

public sealed class Utf8StringWriter : StringWriter 
{ 
    public override Encoding Encoding => Encoding.UTF8; 
} 

Was, warum konnten Sie nicht retten Ihr XML zur Datenbank - Sie müssen uns mehr Details darüber geben, was passiert ist, als Sie es versucht haben, wenn Sie möchten, dass wir es diagnostizieren/beheben können.

+0

Ich ging jetzt detaillierter für das Datenbankproblem. Siehe Frage. – StampedeXV

+2

Sad der 'StringWriter' berücksichtigt die Kodierung nicht, aber trotzdem, danke für eine raffinierte kleine Methode :) – Chau

+2

Und" XML parsing: Zeile 1, Zeichen 38, kann die Kodierung nicht umschalten "kann gelöst werden durch "settings.Indent = false; settings.OmitXmlDeclaration = false; " –

18

Zuallererst, hüte dich davor, alte Beispiele zu finden. Sie haben einen gefunden, der XmlTextWriter verwendet, der ab .NET 2.0 nicht mehr unterstützt wird. XmlWriter.Create sollte stattdessen verwendet werden.

Hier ist ein Beispiel für ein Objekt in eine XML-Spalte Serialisierung:

public void SerializeToXmlColumn(object obj) 
{ 
    using (var outputStream = new MemoryStream()) 
    { 
     using (var writer = XmlWriter.Create(outputStream)) 
     { 
      var serializer = new XmlSerializer(obj.GetType()); 
      serializer.Serialize(writer, obj); 
     } 

     outputStream.Position = 0; 
     using (var conn = new SqlConnection(Settings.Default.ConnectionString)) 
     { 
      conn.Open(); 

      const string INSERT_COMMAND = @"INSERT INTO XmlStore (Data) VALUES (@Data)"; 
      using (var cmd = new SqlCommand(INSERT_COMMAND, conn)) 
      { 
       using (var reader = XmlReader.Create(outputStream)) 
       { 
        var xml = new SqlXml(reader); 

        cmd.Parameters.Clear(); 
        cmd.Parameters.AddWithValue("@Data", xml); 
        cmd.ExecuteNonQuery(); 
       } 
      } 
     } 
    } 
} 
+2

Ich kann das nur einmal abstimmen, aber das verdient die beste Antwort hier zu sein. Am Ende spielt es keine Rolle, welche Kodierung deklariert oder verwendet wird, solange der 'XmlReader' es parsen kann. Es wird vor der Analyse an die Datenbank gesendet, und dann muss die DB nichts über Zeichenkodierungen wissen - UTF-16 oder anders. Beachten Sie insbesondere, dass die XML-Deklarationen nicht mit den Daten in der Datenbank beibehalten werden, unabhängig davon, welche Methode zum Einfügen verwendet wird. Bitte machen Sie keine Verschwendung, indem Sie XML durch zusätzliche Conversions ausführen, wie in anderen Antworten hier und anderswo gezeigt. – ziesemer

+1

Siehe auch: http://StackOverflow.com/a/8998183/751158 – ziesemer

1
public static T DeserializeFromXml<T>(string xml) 
{ 
    T result; 
    XmlSerializerFactory serializerFactory = new XmlSerializerFactory(); 
    XmlSerializer serializer =serializerFactory.CreateSerializer(typeof(T)); 

    using (StringReader sr3 = new StringReader(xml)) 
    { 
     XmlReaderSettings settings = new XmlReaderSettings() 
     { 
      CheckCharacters = false // default value is true; 
     }; 

     using (XmlReader xr3 = XmlTextReader.Create(sr3, settings)) 
     { 
      result = (T)serializer.Deserialize(xr3); 
     } 
    } 

    return result; 
} 
0

es an anderer Stelle abgedeckt worden ist einfach, aber die Codierung Zeile der XML-Quelle auf ‚utf-16‘ Wechsel ermöglicht es die XML, das in den XML-Datentyp eines SQL-Servers eingefügt werden soll.

using (DataSetTableAdapters.SQSTableAdapter tbl_SQS = new DataSetTableAdapters.SQSTableAdapter()) 
{ 
    try 
    { 
     bodyXML = @"<?xml version="1.0" encoding="UTF-8" standalone="yes"?><test></test>"; 
     bodyXMLutf16 = bodyXML.Replace("UTF-8", "UTF-16"); 
     tbl_SQS.Insert(messageID, receiptHandle, md5OfBody, bodyXMLutf16, sourceType); 
    } 
    catch (System.Data.SqlClient.SqlException ex) 
    { 
     Console.WriteLine(ex.Message); 
     Console.ReadLine(); 
    } 
} 

Das Ergebnis ist der gesamte XML-Text in das ‚xml‘ Datentypfeld eingefügt wird, aber die ‚Header‘ Linie entfernt wird. Was Sie in der resultierenden Aufzeichnung sehen, ist nur

<test></test> 

die Serialisierungsmethode Verwendung in dem „Beantwortet“ Eintrag beschrieben ist eine Möglichkeit, die Original-Header im Zielfeld einschließlich, aber das Ergebnis ist, dass der verbleibende XML-Text eingeschlossen in einem XML-Code <string></string>.

Der Tabellenadapter in dem Code ist eine Klasse automatisch mit dem Visual Studio 2013 „Neue Datenquelle hinzufügen gebaut:.. Assistenten, um die fünf Parameter an die Insert-Methode Karte auf Felder in einer SQL Server-Tabelle

+1

Ersetzen? Das ist urkomisch. –

+1

Ernsthaft - tun Sie das nicht. Je. Was wäre, wenn ich eine Prosa in meine XML-Datei einfügen möchte, die "UTF-8" enthält? Sie haben gerade meine Daten in etwas geändert, das ich nicht gesagt habe! –

Verwandte Themen