38

我有一个创建一些 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 中,所以不能使用任何新的框架元素。

4

5 回答 5

80

您需要使用具有适当编码的 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; }
    }
}

这个问题很相似,但并不完全重复。)

编辑:回答评论:将 StringWriterWithEncoding 传递给XmlWriter.Create而不是 StringBuilder,然后在最后调用 ToString() 。

于 2009-01-09T11:24:03.037 回答
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();
            }
        }
于 2013-02-14T08:33:11.747 回答
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());

从这里

于 2013-07-25T04:04:53.033 回答
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;
        }
于 2009-01-09T11:27:58.520 回答
0

我通过将字符串输出到变量然后用 utf-8 替换对 utf-16 的任何引用来解决我的问题(我的应用程序需要 UTF8 编码)。由于您使用的是函数,因此您可以执行类似的操作。我主要使用 VB.net,但我认为 C# 看起来像这样。

return builder.ToString().Replace("utf-16", "utf-8");
于 2016-12-11T18:46:55.127 回答