【问题标题】:Combine few xml files: encoding problems合并几个xml文件:编码问题
【发布时间】:2016-11-16 11:22:54
【问题描述】:

我的应用程序从 web 服务中获取一些像这样的 xml 文件:

<?xml version="1.0" encoding="iso-8859-1"?> 
<root> 
    <person> 
    <!— some elements here —> 
    </person> 
    <person> 
    <!— some elements here —> 
    </person> 
</root>

我将所有这些文件合并到一个文件中,以便在一个根元素下加入所有人员。如果我使用这样的代码:

var readers = files.Select(XmlReader.Create).ToList(); 
var writer = XmlWriter.Create("final.xml"); 
... 
writer.WriteStartDocument(); 
writer.WriteStartElement("root"); 

foreach (var reader in readers) 
{ 
    reader.MoveToContent(); 
    reader.Read(); 
    while (!reader.EOF) 
    { 
        string elementName = reader.Name; 
        if (elementName.Equals("person", StringComparison.OrdinalIgnoreCase)) 
        { 
            writer.WriteNode(reader, false); 
        } 
        else 
        { 
            reader.Read(); 
        } 
    } 
} 

writer.WriteEndElement(); 
writer.WriteEndDocument(); 
... 
//dispose all readers and writers

它工作正常,在最终文件中,我在 xml 序言中有 utf-8。但如果我创建这样的读者:

var readers = files.Select(x => XmlReader.Create(new StreamReader(x))).ToList();

我在 xml prolouge 中有相同的 utf-8,但最终文件中有损坏的数据。例如,不是符号 å 我有�。我试图找出这个问题的原因阅读Joel's article about encodings,但没有结果。为什么它会这样工作?

【问题讨论】:

    标签: c# xml encoding utf-8


    【解决方案1】:

    当您像这样创建XmlReader 时:

    XmlReader.Create("path/to/file.xml")
    

    那么文件的编码将从XML声明中推断出来,所以iso-8859-1。这显然是正确的。

    当您像这样创建XmlReader 时:

    XmlReader.Create(new StreamReader("path/to/file.xml"))
    

    您正在使用采用TextReader 的重载。 TextReader 返回 unicode,因此 XmlReader 无需解码。结果是声明中指定的编码被完全忽略。 the docs中提到了这一点:

    文本阅读器返回一个 Unicode 字符流,因此 XML 阅读器不使用 XML 声明中指定的编码来解码数据流。

    如果你想这样做,你需要为StreamReader指定正确的编码,因为它没有正确检测到这一点:

    new StreamReader("path/to/file.xml", Encoding.GetEncoding("iso-8859-1"));
    

    【讨论】:

    • AFAIK unicode 是字符集,utf-8/iso-8859-1 是编码。在这两种情况下都使用unicode吗?错误的编码是否意味着我从二进制数据中收到错误的数字,最后使用 unicode 字符集解释错误的数字?
    • @mtkachenko 您的文件(这是一个字节负载)被解码为字符串(unicode 字符),然后在您再次将其写入文件时重新编码。解码是这里出了问题,你得到了错误的字符,因为你的StreamReader 使用了错误的解码器(它将默认为 UTF-8,因为没有 BOM 另有指示)。
    • 进程:字节 -> 基于编码的数字 -> 基于字符集的字符串。所以第二步是错误的,最后也是第三步,对吧?这里的错误方式:字节-> utf-8-> unicode。好方法:bytes->iso-8859-1->unicode(或unicode的子集)。对吗?
    • @mtkachenko 没有中间步骤,您只是从字节 -> 字符串再返回。所有编码都来自/来自 unicode,因为这就是 .NET 中的所有字符串。
    • 是的,但是不同的编码可以为一个符号(数字)使用不同的字节数。
    猜你喜欢
    • 2015-02-07
    • 2023-03-12
    • 1970-01-01
    • 2018-03-30
    • 1970-01-01
    • 1970-01-01
    • 2015-09-18
    • 2012-01-12
    • 1970-01-01
    相关资源
    最近更新 更多