Использование StringWriter для сериализации XML
В настоящее время я ищу простой способ сериализации объектов (в C# 3).
я погуглил несколько примеров и придумал что-то вроде:
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 я не мог просто записать в XML-столбец SQL Server 2005 DB.
первый вопрос: есть ли причина, почему я не следует ли использовать StringWriter для сериализации объекта, когда он мне нужен в качестве строки после этого? Я никогда не находил результат с помощью StringWriter при гугле.
второй, конечно: если вы не должны делать это со StringWriter (по каким-либо причинам), что было бы хорошим и правильным способом?
дополнение:
как уже упоминалось в обоих ответах, я далее перейду к проблеме XML в БД.
при записи в базу данных я получил следующее исключение:
система.Данные.SqlClient.Sqlexception в: Синтаксический анализ XML: строка 1, символ 38, невозможно переключить кодировку
строка
<?xml version="1.0" encoding="utf-8"?><test/>
Я взял строку, созданную из XmlTextWriter и просто положить как xml там. Это не сработало (ни с ручной вставкой в БД).
после этого я попробовал ручную вставку (просто запись INSERT INTO ... ) с кодировкой= "utf-16", которая также неудачный. Удаление кодировки полностью сработало тогда. После этого результата я переключился обратно на код StringWriter и вуаля-это сработало.
проблема: я действительно не понимаю, почему.
в Christian Hayter: с этими тестами я не уверен, что мне нужно использовать utf-16 для записи в БД. Не будет ли установка кодировки в UTF-16 (в теге xml) работать тогда?
5 ответов:
при сериализации XML-документа в строку .NET кодировка должна быть установлена в UTF-16. Строки хранятся как UTF-16 внутренне, так что это единственная кодировка, которая имеет смысл. Если вы хотите хранить данные в другой кодировке, вместо этого вы используете массив байтов.
SQL Server работает по аналогичному принципу; любая строка передается в
xml
столбец должен быть закодирован как UTF-16. SQL Server отклонит любую строку, в которой XML-объявление не указывает UTF-16. Если 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, если вы пишете его в файл. У меня есть небольшой класс, чтобы помочь с этим, хотя: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 в базе данных - вы будете иметь чтобы дать нам более подробную информацию о том, что произошло, когда вы пытались, если вы хотите, чтобы мы могли диагностировать/исправить это.
прежде всего, остерегайтесь находить старые примеры. Вы нашли тот, который использует
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".
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", но строка "заголовок" удаляется. То, что вы видите в результирующей записи просто
<test></test>
использование метода сериализации, описанного в записи "ответ", является способом включения исходного заголовка в целевом поле, но результат заключается в том, что оставшийся текст XML заключен в XML
<string></string>
тег.адаптер таблицы в коде-это класс, автоматически созданный с помощью Visual Studio 2013 " Добавить новый источник данных: мастер. Пять параметров метода Insert сопоставляются с полями в таблице SQL Server.