我有一个创建一些XmlDocument的函数:
public string CreateOutputXmlString(ICollection<Field> fields)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.Encoding = Encoding.GetEncoding("windows-1250");
StringBuilder builder = new StringBuilder();
XmlWriter writer = XmlWriter.Create(builder, settings);
writer.WriteStartDocument();
writer.WriteStartElement("data");
foreach (Field field in fields)
{
writer.WriteStartElement("item");
writer.WriteAttributeString("name", field.Id);
writer.WriteAttributeString("value", field.Value);
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.Flush();
writer.Close();
return builder.ToString();
}
我设置了一个编码,但在创建XmlWriter后,它确实有utf-16编码。我知道这是因为字符串(和我猜想的StringBuilder)是用utf-16编码的,你无法改变它。
那么如何在编码属性设置为“windows-1250”的情况下轻松创建此xml?它甚至不必在这种编码中编码,它只需具有指定的属性。
编辑:它必须在.Net 2.0中,因此不能使用任何新的框架元素。
答案 0 :(得分:72)
您需要使用具有适当编码的StringWriter。不幸的是StringWriter不允许你直接指定编码,所以你需要一个这样的类:
public sealed class StringWriterWithEncoding : StringWriter
{
private readonly Encoding encoding;
public StringWriterWithEncoding (Encoding encoding)
{
this.encoding = encoding;
}
public override Encoding Encoding
{
get { return encoding; }
}
}
(This question相似但不太重复。)
编辑:回答评论:将StringWriterWithEncoding传递给XmlWriter.Create而不是StringBuilder,然后在最后调用ToString()。
答案 1 :(得分:5)
只是为什么会这样做的一些额外解释。
字符串是字符序列,而不是字节。字符串本身不是“编码”的,因为它们使用的字符存储为Unicode代码点。编码不会在字符串级别发出感知。
编码是从一系列代码点(字符)到字节序列的映射(用于存储在基于字节的系统(如文件系统或内存)上)。该框架不允许您指定编码,除非有令人信服的理由,比如使16位代码点适合基于字节的存储。
因此,当您尝试将XML编写到StringBuilder中时,实际上是在构建XML字符序列并将其编写为字符序列,因此不执行编码。因此,没有编码字段。
如果要使用编码,XmlWriter必须写入Stream。
关于你在MemoryStream中找到的解决方案,没有任何违法行为,但它只是在手臂上移动并移动热空气。您使用'windows-1252'对代码点进行编码,然后将其解析回代码点。唯一可能发生的变化是未在windows-1252中定义的字符转换为'?'这个过程中的人物。
对我而言,正确的解决方案可能是以下方案。根据您的函数用途,您可以将Stream作为参数传递给函数,以便调用者决定是将其写入内存还是文件。所以它会这样写:
public static void WriteFieldsAsXmlDocument(ICollection fields, Stream outStream)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.Encoding = Encoding.GetEncoding("windows-1250");
using(XmlWriter writer = XmlWriter.Create(outStream, settings)) {
writer.WriteStartDocument();
writer.WriteStartElement("data");
foreach (Field field in fields)
{
writer.WriteStartElement("item");
writer.WriteAttributeString("name", field.Id);
writer.WriteAttributeString("value", field.Value);
writer.WriteEndElement();
}
writer.WriteEndElement();
}
}
答案 2 :(得分:5)
MemoryStream memoryStream = new MemoryStream();
XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.Encoding = Encoding.UTF8;
XmlWriter xmlWriter = XmlWriter.Create(memoryStream, xmlWriterSettings);
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("root", "http://www.timvw.be/ns");
xmlWriter.WriteEndElement();
xmlWriter.WriteEndDocument();
xmlWriter.Flush();
xmlWriter.Close();
string xmlString = Encoding.UTF8.GetString(memoryStream.ToArray());
答案 3 :(得分:3)
我实际上用MemoryStream解决了这个问题:
public static string CreateOutputXmlString(ICollection<Field> fields)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.Encoding = Encoding.GetEncoding("windows-1250");
MemoryStream memStream = new MemoryStream();
XmlWriter writer = XmlWriter.Create(memStream, settings);
writer.WriteStartDocument();
writer.WriteStartElement("data");
foreach (Field field in fields)
{
writer.WriteStartElement("item");
writer.WriteAttributeString("name", field.Id);
writer.WriteAttributeString("value", field.Value);
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.Flush();
writer.Close();
writer.Flush();
writer.Close();
string xml = Encoding.GetEncoding("windows-1250").GetString(memStream.ToArray());
memStream.Close();
memStream.Dispose();
return xml;
}
答案 4 :(得分:0)
我通过将字符串输出到变量然后用utf-8替换对utf-16的任何引用来解决我的问题(我的app需要UTF8编码)。既然你正在使用一个函数,你可以做类似的事情。我主要使用VB.net,但我认为C#看起来像这样。
return builder.ToString().Replace("utf-16", "utf-8");