Подтвердить что ты не робот

Сериализация XML с помощью XmlWriter через StringBuilder является utf-16, а через Stream - utf-8?

Я был удивлен, когда столкнулся с ним, и написал консольное приложение, чтобы проверить его и убедиться, что я ничего не делал.

Кто-нибудь может это объяснить?

Здесь код:

using System;    
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace ConsoleApplication1
{
    public class Program
    {
        static void Main(string[] args)
        {
            var o = new SomeObject { Field1 = "string value", Field2 = 8 };

            Console.WriteLine("ObjectToXmlViaStringBuilder");
            Console.Write(ObjectToXmlViaStringBuilder(o));
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("ObjectToXmlViaStream");
            Console.Write(StreamToString(ObjectToXmlViaStream(o)));
            Console.ReadKey();
        }

        public static string ObjectToXmlViaStringBuilder(SomeObject someObject)
        {
            var output = new StringBuilder();
            var settings = new XmlWriterSettings { Encoding = Encoding.UTF8, Indent = true };

            using (var xmlWriter = XmlWriter.Create(output, settings))
            {
                var serializer = new XmlSerializer(typeof(SomeObject));
                var namespaces = new XmlSerializerNamespaces();

                xmlWriter.WriteStartDocument();
                xmlWriter.WriteDocType("Field1", null, "someObject.dtd", null);
                namespaces.Add(string.Empty, string.Empty);
                serializer.Serialize(xmlWriter, someObject, namespaces);
            }

            return output.ToString();
        }

        private static string StreamToString(Stream stream)
        {
            var reader = new StreamReader(stream);
            return reader.ReadToEnd();
        }

        public static Stream ObjectToXmlViaStream(SomeObject someObject)
        {
            var output = new MemoryStream();
            var settings = new XmlWriterSettings { Encoding = Encoding.UTF8, Indent = true };

            using (var xmlWriter = XmlWriter.Create(output, settings))
            {
                var serializer = new XmlSerializer(typeof(SomeObject));
                var namespaces = new XmlSerializerNamespaces();

                xmlWriter.WriteStartDocument();
                xmlWriter.WriteDocType("Field1", null, "someObject.dtd", null);
                namespaces.Add(string.Empty, string.Empty);
                serializer.Serialize(xmlWriter, someObject, namespaces);
            }

            output.Seek(0L, SeekOrigin.Begin);

            return output;
        }

        public class SomeObject
        {
            public string Field1 { get; set; }
            public int Field2 { get; set; }
        }
    }
}

Это результат:

ObjectToXmlViaStringBuilder

<?xml version="1.0" encoding="utf-16"?>
<!DOCTYPE Field1 SYSTEM "someObject.dtd">
<SomeObject>
<Field1>string value</Field1>
<Field2>8</Field2>
</SomeObject>

ObjectToXmlViaStream

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Field1 SYSTEM "someObject.dtd">
<SomeObject>
<Field1>string value</Field1>
<Field2>8</Field2>
</SomeObject>
4b9b3361

Ответ 1

Когда вы создаете XmlWriter вокруг a TextWriter, XmlWriter всегда использует кодировку базового TextWriter. Кодировка StringWriter всегда является UTF-16, так как так, как строки .NET кодируются внутри.

Когда вы создаете XmlWriter вокруг a Stream, для Stream нет кодировки, поэтому он использует кодировку, указанную в XmlWriterSettings.

Ответ 2

Самое изящное решение для меня - записать в memystream, а затем использовать кодировку для кодирования потока для любой кодировки. так

        using (MemoryStream memS = new MemoryStream())
        {
            //set up the xml settings
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.OmitXmlDeclaration = OmitXmlHeader;

            using (XmlWriter writer = XmlTextWriter.Create(memS, settings))
            {
                //write the XML to a stream
                xmlSerializer.Serialize(writer, objectToSerialize);
                writer.Close();
            }
            //encode the memory stream to xml
            retString.AppendFormat("{0}", encoding.GetString(memS.ToArray()));
            memS.Close();
        }

где кодирование происходит в... encoding.GetString(memS.ToArray())...

Ответ 3

По возможности, XmlWriter использует кодировку базового потока. Он написал UTF-8 данные потоку, который, как он знал, был UTF-16, вы попали в беспорядок. Запись данных UTF-16 в поток UTF-8 также вызывает проблемы, особенно для сред, которые используют строки с нулевым завершением (например, C/С++).

StringBuilder/StringWriter представляет поток UTF-16 для XmlWriter, поэтому XmlWriter игнорирует ваш запрошенный параметр и использует его.

На практике я обычно не выделяю заголовок, таким образом, я могу использовать StringBuilder снизу и сохранять несколько строк кода с переключением кодировок.