反序列化 XML 时忽略指定的编码

发布于 2024-09-29 18:18:58 字数 1846 浏览 4 评论 0原文

我正在尝试通过套接字读取从外部接口接收到的一些 XML。 问题是 XML 标头中指定的编码错误(显示为 iso-8859-1,但实际上是 utf-16BE)。据记录编码是utf-16BE,但显然他们忘记设置正确的编码。

为了在反序列化时忽略编码,我使用了如下所示的 StringReader:

    private static T DeserializeXmlData<T>(byte[] xmlData)
    {
        var xmlString = Encoding.BigEndianUnicode.GetString(xmlData);
        using (var reader = new StringReader(xmlString))
        {
            reader.ReadLine(); // Eat header line
            using (var xmlReader = XmlReader.Create(reader))
            {
                var serializer = new XmlSerializer(typeof(T));
                return (T)serializer.Deserialize(xmlReader);
            }
        }
    }

上面的代码实际上工作正常,但我不喜欢通过调用 ReadLine 跳过标题行的部分。 是否有更简单的方法来绕过 XML 标头中指定的编码?

使用 StreamReader 的解决方案

通过使用 StreamReader,我可以覆盖 XML 标头中指定的编码。指定或不指定 XmlReaderSettings.IgnoreProcessingInstructions 没有任何区别。 有趣的是,如果 StreamReader 找到 unicode 字节顺序标记,则它会忽略指定的编码。

回顾一下:

  • 如果使用 TextReader 初始化 XmlReader,则忽略 XML 标头编码。
  • 如果使用 StringReader,并且存在 unicode 字节顺序标记,则 XmlReader 将失败。
  • 如果使用 StreamReader,unicode 字节顺序标记将覆盖 StreamReader 编码。
  • 使用 TextReader 时,XmlReaderSettings.IgnoreProcessingInstructions = true 没有什么区别。

总之,最可靠的解决方案似乎是使用 StreamReader,因为它使用字节顺序标记(如果存在)。

    private static T DeserializeXmlData<T>(byte[] xmlData)
    {
        using (var xmlDataStream = new MemoryStream(xmlData))
        {
            using (var reader = new StreamReader(xmlDataStream, Encoding.BigEndianUnicode))
            {
                using (var xmlReader = XmlReader.Create(reader))
                {
                    var serializer = new XmlSerializer(typeof (T));
                    return (T) serializer.Deserialize(xmlReader);
                }
            }
        }
    }

I am trying to read some XML received from an external interface over a socket.
The problem is that the encoding is specified wrong in the XML-header (it says iso-8859-1, but it is utf-16BE). It is documented that the encoding is utf-16BE, but apparently they forgot to set the correct encoding.

To ignore the encoding when I deserialize I use a StringReader like this:

    private static T DeserializeXmlData<T>(byte[] xmlData)
    {
        var xmlString = Encoding.BigEndianUnicode.GetString(xmlData);
        using (var reader = new StringReader(xmlString))
        {
            reader.ReadLine(); // Eat header line
            using (var xmlReader = XmlReader.Create(reader))
            {
                var serializer = new XmlSerializer(typeof(T));
                return (T)serializer.Deserialize(xmlReader);
            }
        }
    }

The above actually works fine, but I don't like the part where I just skip the header line by calling ReadLine.
Is there a less brittle way to bypass the encoding specified in the XML-header?

Solution with StreamReader

By using a StreamReader, I can override the encoding specified in the XML-header. Specifying XmlReaderSettings.IgnoreProcessingInstructions or not did not do any difference.
Interestingly the StreamReader ignores the specified encoding if it finds a unicode byte-order mark.

To recap:

  • If the XmlReader is initialized with a TextReader, XML-header encoding is ignored.
  • If a StringReader is used, the XmlReader fails if a unicode byte-order mark exists.
  • If a StreamReader is used, a unicode byte-order mark overrides the StreamReader encoding.
  • XmlReaderSettings.IgnoreProcessingInstructions = true doesn't make a difference when using a TextReader.

In conclusion, the most robust solution seems to be using a StreamReader, since it uses the byte-order mark, if present.

    private static T DeserializeXmlData<T>(byte[] xmlData)
    {
        using (var xmlDataStream = new MemoryStream(xmlData))
        {
            using (var reader = new StreamReader(xmlDataStream, Encoding.BigEndianUnicode))
            {
                using (var xmlReader = XmlReader.Create(reader))
                {
                    var serializer = new XmlSerializer(typeof (T));
                    return (T) serializer.Deserialize(xmlReader);
                }
            }
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

成熟稳重的好男人 2024-10-06 18:18:58

我想我只需使用一个 StreamReader,用正确的编码构造并将其传递给 XmlReader.Create(TextStream) 方法:

 using (var sr = new StreamReader(@"c:\temp\bad.xml", Encoding.BigEndianUnicode)) {
     using (var xr = XmlReader.Create(sr, new XmlReaderSettings())) {
         // etc...
     }
 }

I think I'd just use a StreamReader, constructed with the right encoding and pass that to the XmlReader.Create(TextStream) method:

 using (var sr = new StreamReader(@"c:\temp\bad.xml", Encoding.BigEndianUnicode)) {
     using (var xr = XmlReader.Create(sr, new XmlReaderSettings())) {
         // etc...
     }
 }
木有鱼丸 2024-10-06 18:18:58

如果没有其他相关处理指令,您可以通过设置 XmlReaderSettings.IgnoreProcessingInstructions

If there are no other relevant processing instructions, you can just ignore them by setting XmlReaderSettings.IgnoreProcessingInstructions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文