それに遭遇したときは驚き、コンソールアプリケーションを作成してチェックし、他に何もしていないことを確認しました。
誰かがこれを説明できますか?
コードは次のとおりです。
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>
XmlWriter
の周りにTextWriter
を作成すると、XmlWriter
は常に基になるTextWriter
のエンコーディングを使用します。 StringWriter
のエンコードは常にUTF-16です。これは、.NET文字列が内部でエンコードされる方法だからです。
XmlWriter
の周囲にStream
を作成する場合、Stream
にエンコードが定義されていないため、XmlWriterSettings
で指定されたエンコードが使用されます。
私にとって最も洗練された解決策は、メモリストリームに書き込み、エンコーディングを使用してストリームを必要なエンコーディングにエンコードすることです。そのようです
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())..で行われます。
可能な場合、XmlWriterは基になるストリームのエンコーディングを使用します。 UTF-8データをUTF-16であることがわかっているストリームに書き込んだ場合、混乱してしまいます。 UTF-16データをUTF-8ストリームに書き込むと、特にnullで終了する文字列を使用する環境(C/C++など)で問題が発生します。
StringBuilder/StringWriterはUTF-16ストリームをXmlWriterに提示するため、XmlWriterは要求された設定を無視してそれを使用します。
実際には、私は通常ヘッダーを発行しません。そうすれば、その下でStringBuilderを使用して、エンコーディングの切り替えをいじる数行のコードを節約できます。