使用StringWriter进行XML序列化

我目前正在寻找一个简单的方法来序列化对象(在C#3中)。

我search了一些例子,并提出了类似的东西:

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()); 

看完这个问题后,我问自己,为什么不使用StringWriter? 这似乎更容易。

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

另一个问题是,第一个例子生成的XML我不能只写入SQL Server 2005数据库的XML列。

第一个问题是:是否有一个原因,我不应该使用StringWriter序列化一个对象,当我需要它作为一个string后? 当使用GoogleWriter时,我从来没有find一个结果。

其次是,如果你不应该用StringWriter(不pipe什么原因)这样做,这将是一个很好的和正确的方法?


加成:

正如这两个答案已经提到,我将进一步进入XML到DB的问题。

写入数据库时​​,出现以下exception:

System.Data.SqlClient.SqlException:XMLparsing:行1,字符38,无法切换编码

对于string

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

我从XmlTextWriter创build的string,只是把它放在那里。 这一个没有工作(既没有手动插入数据库)。

之后我尝试手动插入(只是写入INSERT INTO …)与编码=“utf-16”也失败了。 删除编码完全工作。 之后,我转回到StringWriter代码,瞧 – 它的工作。

问题:我不明白为什么。

在Christian Hayter:有了这些testing,我不确定是否必须使用utf-16写入数据库。 不会将编码设置为UTF-16(在xml标签中)工作吗?

将XML文档序列化为.NETstring时,编码必须设置为UTF-16。 string在内部存储为UTF-16,所以这是唯一有意义的编码。 如果要以不同的编码存储数据,则应使用字节数组。

SQL Server的工作原理类似, 任何传递到xml列的string都必须编码为UTF-16。 SQL Server将拒绝任何XML声明不指定UTF-16的string。 如果XML声明不存在,那么XML标准要求默认为UTF-8,所以SQL Server也会拒绝。

考虑到这一点,下面是一些转换的实用方法。

 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); } } } 

StringWriter一个问题是,默认情况下, 它不允许你设置它发布的编码 – 所以你最终可以用一个XML文档来宣传它的编码为UTF-16,这意味着你需要把它编码为UTF-16 if你把它写入一个文件。 我有一个小class来帮忙,但是:

 public sealed class StringWriterWithEncoding : StringWriter { public override Encoding Encoding { get; } public StringWriterWithEncoding (Encoding encoding) { Encoding = encoding; } } 

或者如果你只需要UTF-8(这是我经常需要的):

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

至于为什么你不能将XML保存到数据库中 – 如果你希望我们能够诊断/修复它,你必须给我们提供更多关于你尝试时发生的事情的细节。

首先,要小心寻找古老的例子。 你已经find一个使用XmlTextWriter ,从.NET 2.0开始已经弃用了。 应该使用XmlWriter.Create来代替。

下面是将对象序列化到XML列的示例:

 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(); } } } } } 
 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; } 

它可能在其他地方已经被覆盖,但是简单地将XML源的编码行更改为“utf-16”允许将XML插入到SQL Server的“xml”数据types中。

 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(); } } 

结果是所有的XML文本都被插入到“xml”数据types字段中,但“标题”行被删除。 你在结果logging中看到的只是

 <test></test> 

使用“已答复”条目中描述的序列化方法是将原始标题包括在目标字段中的一种方式,但结果是剩余的XML文本被包含在XML <string></string>标记中。

代码中的表格适配器是一个使用Visual Studio 2013“添加新数据源:向导”自动构build的类。Insert方法的五个参数映射到SQL Server表中的字段。