【问题标题】:How default is the default encoding (UTF-8) in the XML Declaration?XML 声明中的默认编码 (UTF-8) 有多默认?
【发布时间】:2013-04-28 00:49:04
【问题描述】:

我知道the default encoding of XML is UTF-8。所有 XML 消费者都必须如此等等。所以这不仅仅是 XML 是否有默认编码的问题。

我也知道文档开头的the XML-Declarataion <?xml version="1.0" ... ?> 本身是可选的。并且指定其中的编码也是可选的。

所以我问自己以下两个 XML 声明是否是完全相同的两个表达式:

<?xml version="1.0"?>
<?xml version="1.0" encoding="UTF-8"?>

根据我目前的理解,我会说这些是等价的,但我不知道。 是否在某处指定了这两个声明的等价性?

(假设这两个示例行都​​是 XML 文档的第一行,前面是任何(零)字节并且是 UTF-8 编码的)

【问题讨论】:

  • 幸运的是 UTF-8 是默认的。当读取 XML 文档并以另一种编码写入时,大多数情况下该属性也会被修补。完全没有问题,我无法想象为什么人们经常看到编码属性。版本很重要;更高版本允许标签名称,如&lt;café&gt;。
  • 我不是在问这个,因为我这里的字符编码有问题。我只是想知道这些对我来说是否相同,是否已指定。这样就可以测试我的软件的一致性。

标签: xml utf-8


【解决方案1】:

简短的回答

在没有外部编码信息的 UTF-8 编码文档的非常特殊的情况下(我从 cmets 了解到这是您感兴趣的内容),这两种声明之间没有区别。

不过,长答案要有趣得多。

规范是怎么说的

如果您查看Appendix F1 of the XML specification,则说明了在没有外部编码信息时确定编码应遵循的过程。

如果文档被编码为 UTF 变体之一,解析器应该能够从字节顺序标记或 XML 声明的开头检测前 4 个字节内的编码。

但是,根据规范,它仍然应该读取编码声明。

在上述不需要读取编码声明来确定编码的情况下,第 4.3.3 节仍然要求读取编码声明(如果存在)并检查编码名称以匹配实体的实际编码.

如果不匹配,根据section 4.3.3:

...对于包含编码声明的实体以声明中指定的编码以外的编码呈现给 XML 处理器,这是一个致命错误

编码 UTF-16,声明 UTF-8

让我们看看当我们创建一个编码为 UTF-16 但编码声明设置为 UTF-8 的 XML 文档时实际发生的情况。

Opera、Firefox 和 Chrome 都将文档解释为 UTF-16,忽略编码声明。 Internet Explorer(至少版本 9),显示一个空白文档,但没有实际错误。

因此,如果您在 UTF-8 文档中包含 UTF-8 编码声明,并且稍后有人将其转换为 UTF-16,它将在大多数浏览器中工作,但在 IE 中会失败(而且,我假设,大多数 Microsoft XML API)。如果你关闭了编码声明,你会没事的。

从技术上讲,我认为 IE 是最准确的。它不显示错误的事实可能是因为错误发生在编码级别而不是 XML 级别。假设它尽最大努力将 UTF-16 字符解释为 UTF-8,未能找到任何解码的字符,并最终将空字符序列传递给 XML 解析器。

编码为 UTF-8,否则声明

您现在可能认为 Firefox、Chrome 和 Opera 完全忽略了编码声明,但情况并非总是如此。

如果您将文档编码为 UTF-8(带有字节顺序标记,因此它不会像其他任何东西一样),但将编码声明设置为 Latin1,所有浏览器都会成功地将内容解码为 Latin1,忽略 UTF- 8 物料清单。

这对我来说似乎是正确的。 BOM 字符在 Latin1 中无效的事实只是意味着它们在字符解码级别被静默删除。

这不适用于 UTF-8 文档上所有声明的编码。如果声明的编码是 UTF-16,我们将返回 Opera、Firefox 和 Chrome 忽略声明的编码,而 Internet Explorer 返回一个空白文档。

基本上,任何让 IE 返回空白文档的东西都会让其他浏览器忽略声明的编码。

其他不一致的地方

还值得一提的是字节顺序标记的重要性。根据section 4.3.3 of the spec:

以 UTF-16 编码的实体必须 [...] 以字节顺序标记开头

但是,如果您尝试读取没有 BOM 的 UTF-16 编码的 XML 文档,大多数浏览器仍然会接受它为有效的。只有 Firefox 将其报告为 XML 解析错误。

外部编码信息

到目前为止,我们一直在考虑没有外部编码信息时会发生什么,但是,正如其他人所提到的,如果文档是通过 HTTP 接收或包含在某种 MIME 信封中,则编码信息来自这些来源应优先于文档编码。

RFC3023 中描述了各种 XML MIME 类型的大部分细节。但是,实际情况与指定的有所不同。

首先,带有省略字符集参数的 text/xml 应使用 US-ASCII 字符集,但该要求几乎总是被忽略。浏览器通常会使用 XML 编码声明的值,如果没有,则默认为 UTF-8。

其次,如果文档上有 UTF-8 BOM,并且 XML 编码声明是 UTF-8 或不包括在内,则文档将被解释为 UTF-8,无论 Content- 中使用的字符集如何输入。

只有在没有 BOM 并且在 Content-Type 中指定了明确的字符集时,才会优先使用来自 Content-Type 的编码。

无论如何,在 UTF-8 文档中包含 UTF-8 XML 编码声明与根本没有编码声明没有任何不同(涉及 Content-Type)。

【讨论】:

  • 规范确实在第 4.3.3 节中说明了如果编码不匹配会发生什么情况:“在没有外部传输协议(例如 HTTP 或 MIME)提供的信息的情况下,它是一个包含编码声明的实体的致命错误,该编码声明以声明中指定的编码以外的编码呈现给 XML 处理器 [...]” 之后:“如果确定了 XML 实体,这是一个致命错误(通过默认, 编码声明或更高级别的协议) 以某种编码但包含在该编码中不合法的字节序列。"
【解决方案2】:

孤立地,两者是等价的。您已经引用了规范的相关部分,表明这两个声明是等效的。

但是 XML 可以有一个信封,例如 HTTP Content-Type 标头。 The W3C specifies 此信封信息优先于文件中的任何其他声明。例如,如果您通过 http 检索 XML,您可能会得到以下信息:

HTTP/1.1 200 OK
Content-Type: text/xml

<root/>

在这种情况下,应将 XML 读取为 ascii,因为 text/* mime 类型的默认字符集是 ascii。这就是为什么你应该使用application/xml mime 类型——这些默认为 utf-8。 “应用程序”前缀意味着相关的应用程序规范定义了默认编码之类的东西。 (即 XML 规范接管。)对于text/* mime 类型,默认值为 ascii,并且必须在 mime 类型中包含 charset 参数才能更改字符集。

这是另一个案例:

HTTP/1.1 200 OK
Content-Type: text/xml; charset=win-1252

<?xml version="1.0" encoding="utf-8"?>
<root/>

在这种情况下,符合标准的 XML 处理器应该将该文件读取为 win-1252,不是 utf-8。

另一种情况:

HTTP/1.1 200 OK
Content-Type: application/xml

<?xml version="1.0" encoding="win-1252"?>
<root/>

这里的编码是win-1252。

HTTP/1.1 200 OK
Content-Type: application/xml; charset=ascii

<?xml version="1.0" encoding="win-1252"?>
<root/>

这里的编码是ascii。

【讨论】:

  • 换句话说,一旦有了 DOM,原始文档的编码就无关紧要了。 encoding 是声明所说的内容(如 standalone 或 version),actualEncoding 是解析器解析它的方式,但所有字符串都已从文档编码转换为原生字符串。
  • 我不确定你的意思。正如我所说,有两种不同的 DOM 属性。一个是来自处理指令的数据,另一个是来自解析器的数据。如果 XML 文档中没有写入 encoding="....",则 DOMDocument.encoding 没有值,但 DOMDocument.actualEncoding 将具有解析器用于解析文档的编码。这就是这里发生的一切。请记住,XML 规范不是以 DOM 为中心的,因此在比较文档时,您不应该过多地考虑精确的 DOM 相等性。
  • 是的,但是 DOM 选择区分“encoding xml 声明中的参数”和“编码使用的解析器”,因为您可以看到它们可能不同。 XML 信息集(相对于 DOM)在 xml 声明中不包含 encoding 参数,仅包含“解析器使用的内容”信息。但是,如果没有 xml 声明,两者都可以有 standalone 和 version 没有价值。我不知道为什么这让你如此兴奋!
  • 这不是 xml 解析问题(xml 已经被解析),而是您的特定 DOM 库的粗俗。再一次,xmlEncoding 不是标准的。
  • 你是对的,它是xmlEncoding 和inputEncoding。现在不确定我在哪里读到它是encoding 和actualEncoding。您可以在 infoset mapping 中看到 xmlEncoding/encoding='...' 不是 XML 信息集的一部分。
【解决方案3】:

如果第二个声明到达已被检测为具有非 UTF-8 兼容编码(例如 UTF-16)的文档的开头,则拒绝第二个声明并非不合理。但是,鉴于您声明文档是 UTF-8 编码的,how they would be treated 之间没有区别。

在这两种情况下,外部指定的编码都将优先;两份文件仍将被同等对待。

【讨论】:

  • 感谢您抽出宝贵时间回答,但我有两个问题:首先,您链接的部分不规范。其次——也是更重要的——你写了输入字符串的字符编码并猜测它。我的问题不是关于那个,而是关于 XML 编码,即声明的编码。以及缺失的声明在多大程度上根本不是缺失的声明。
  • 你的问题的答案是肯定的,它们是一样的。我正在写关于检测编码的文章,以便为一个非常相似的案例提供更多细节,即使它比你所要求的更笼统。我认为 4.3.3 的规范“对于包含编码声明的实体以声明中指定的编码以外的编码呈现给 XML 处理器,或者对于既不以字节顺序标记也不以字节顺序标记开头的实体,这是一个致命错误。使用 UTF-8 以外的编码的编码声明”证实了这一点。
【解决方案4】:

我阅读the spec 的方式是,UTF-8 不是 XML 声明中的默认编码。它只是“既不以字节顺序标记也不以编码声明开头的实体”的默认编码。如果一个文档是 UTF-16 并且有一个 BOM,它可能有一个没有编码声明或根本没有 XML 声明的 XML 声明,但仍然是有效的 XML。

仅对于没有 BOM 的文档,您提到的两个 XML 声明应该是等效的。

【讨论】:

  • 这就是为什么你会在问题的末尾找到 "(考虑这两个示例行都​​是 XML 文档的第一行,前面是任何(零)字节并且是 UTF- 8 编码)" :)
  • 没问题,这可能会发生。
猜你喜欢
  • 2014-04-23
  • 2016-08-06
  • 2012-03-10
  • 2012-02-01
  • 2015-04-08
  • 1970-01-01
  • 1970-01-01
  • 2014-02-09
  • 2015-04-14
相关资源
最近更新 更多