【问题标题】:Difference between XmlDocument and XDocument handling �XmlDocument 和 XDocument 处理的区别 �
【发布时间】:2015-10-22 17:38:46
【问题描述】:

我一直在尝试加载一个包含一些 null('') 字符的 xml 文件。我试过了——

  XmlDocument document = new XmlDocument();
  document.LoadXml(xmlString);

XDocument.Load(stringReader);

XmlDocument.LoadXml() 方法成功加载 xml 文档,而 XDocument.Load() 方法为相同的 xml 字符串提供 XmlException

要重现的示例代码:

string xmlFile = @"C:\dummyData.xml";

        string xmlString = File.ReadAllText(xmlFile);

        XmlDocument document = new XmlDocument();
        document.LoadXml(xmlString); //Work

        XDocument.Parse(xmlString); // Didn't work.

        using (StringReader reader = new StringReader(xmlString))
        {
            XDocument.Load(reader);
        }

Xml 文件

Copy the content of xml file from here

【问题讨论】:

  • 您是在尝试报告错误(因为两者都应该失败)还是在寻找解决方法或其他什么?
  • document.LoadXml(xmlString) 对应的方法是XDocument.Parse(xmlString)
  • @AlexeiLevenkov:第一个选项是实际工作,所以我的问题是为什么 XDocument 无法加载 XmlDocument 可以加载的 xml 文件。
  • @ThomasWeller: '.',十六进制值 0x00,是无效字符。
  • @ThomasWeller :

标签: c# .net xml linq-to-xml


【解决方案1】:

为什么 是个问题

按照 W3C 的定义,Entities

CharRef ::=   '&#' [0-9]+ ';'
            | '&#x' [0-9a-fA-F]+ ';'

所以乍一看,� 这样的实体看起来不错。

但你需要阅读定义:

[定义:字符引用是指 ISO/IEC 10646 字符集中的特定字符,例如无法从可用输入设备直接访问的字符。]

所以字符引用需要指向 ISO/IEC 10646 字符,即linked

使用字符引用引用的字符必须与 Char 的产生式相匹配。

幸运的是Char 在同一个文档中并定义为:

Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]

因此,正如Martin Honnen 之前提到的,C# 中的\0 字符和转义版本�� 都不允许在XML 文档中使用。

XML 解析器现实

一些解析器可能会忽略上述规则的一部分,并且不完全遵守标准。

问题的真正根源

您发布的 XML 似乎包含图像/绘图:

<?xml version="1.0" encoding="utf-8"?>
<TestData>
        <Images>
            <Drawings>
&lt;?xml version="1.0"?&gt;
&lt;ArrayOfMarkerState &gt;
&lt;/ArrayOfMarkerState&gt;
&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;</Drawings>
        </Images>
            <Date>2015-10-20T17:19:05.2656609+05:30</Date>
</TestData>

像素图形的本质是它们包含二进制数据。

不熟悉 XML 并面临在 XML 中嵌入二进制数据问题的开发人员很快会认为任何字节都可以编码为&amp;#x00; ... &amp;#xFF;

不幸的是,这是完全错误的。为什么?嗯,因为上面的 W3C 定义。

除此之外,这在大小方面甚至是一个坏主意。即使它可以工作,像这样编码的字节在 XML 中也需要 6 个字节。

解决原来的问题

二进制数据不能作为 XML 实体进入 XML 文档,所以让我们找到一些可行的并且需要小于 +500% 的大小增加。

答案是Base64。 Base64 的大小大约增加了 +33%。

编码这 47 个&amp;#x0; 字节会导致

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=

与原来的 235 个字节相比,它只有 64 个字节长。

【讨论】:

    【解决方案2】:

    在 XML 中不允许字符引用 &amp;#x0;(至少 Microsoft 支持的 XML 1.0)。但是对于遗留支持,我认为使用XmlReaderSettings 创建的XmlReaderXmlReader 不检查字符可以加载此类标记。 XmlDocument 使用这样的 XmlReader 而 XDocument 没有。

    【讨论】:

    • 当然,请参阅w3.org/TR/xml/#charsets,它将字符定义为` #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]`.
    • @MartinHonnen:这是否意味着 XmlDocument 只是忽略了这样的字符,而 XDocument 没有。
    • 旁注:0 对于 XML 1.1 也无效 - w3.org/TR/2006/REC-xml11-20060816/#charsets
    • XmlDocumentXDocument 都不解析 XML 本身,它是由 XmlReader 实现完成的。 LoadXmlXmlDocument 使用的那个我认为是遗留的new XmlTextReader,而XDocument 使用的那个是用XmlReader.Create 创建的一个普通的,它更好地实现了 XML 规范。
    • @AlexeiLevenkov,是的,你是对的,但我只记得 XML 1.1 允许几个控制字符作为 XML 1.0 不允许的字符引用,所以我的文字有点含糊答案。
    猜你喜欢
    • 2010-12-05
    • 1970-01-01
    • 2011-05-21
    • 1970-01-01
    • 2011-04-22
    • 1970-01-01
    • 2017-06-04
    • 1970-01-01
    • 2010-09-30
    相关资源
    最近更新 更多