web-dev-qa-db-ja.com

StringBuilderを介したXmlWriterでのXMLシリアル化はutf-16ですが、Streamを介したXMLは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>
22
H.Wolper

XmlWriterの周りにTextWriterを作成すると、XmlWriterは常に基になるTextWriterのエンコーディングを使用します。 StringWriterのエンコードは常にUTF-16です。これは、.NET文字列が内部でエンコードされる方法だからです。

XmlWriterの周囲にStreamを作成する場合、Streamにエンコードが定義されていないため、XmlWriterSettingsで指定されたエンコードが使用されます。

30
Thomas Levesque

私にとって最も洗練された解決策は、メモリストリームに書き込み、エンコーディングを使用してストリームを必要なエンコーディングにエンコードすることです。そのようです

        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())..で行われます。

4
Coby

可能な場合、XmlWriterは基になるストリームのエンコーディングを使用します。 UTF-8データをUTF-16であることがわかっているストリームに書き込んだ場合、混乱してしまいます。 UTF-16データをUTF-8ストリームに書き込むと、特にnullで終了する文字列を使用する環境(C/C++など)で問題が発生します。

StringBuilder/StringWriterはUTF-16ストリームをXmlWriterに提示するため、XmlWriterは要求された設定を無視してそれを使用します。

実際には、私は通常ヘッダーを発行しません。そうすれば、その下でStringBuilderを使用して、エンコーディングの切り替えをいじる数行のコードを節約できます。

2
kͩeͣmͮpͥ ͩ