Использование 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 83

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.