级别: 初级 Arnaud Le Hors (lehors@us.ibm.com), 随需应变标准管理, IBM
2004 年 5 月 01 日 本文中,软件工程师 Arnaud Le Hors 介绍了 XML 1.1 和 Namespaces 1.1 的内容、带来的变化,以及对其他规范和用户的影响。
2004 年 2 月 4 日,W3C 可以说是秘密地发布了一个新的推荐标准,称为“Extensible Markup Language (XML) 1.1”。该规范为当今无所不在的 XML 格式定义了一个新的版本。既然 XML 非常重要,人们可能认为这应该会引起很大的混乱,但是几个月之后,仍只有相对不多的人知道 XML 1.1 的存在。为什么呢?
本文就来回答这个问题,说明 XML 1.0 和 XML 1.1 之间的不同,并告诉您对于这一新规范和它的姊妹规范,Namespaces in XML 1.1,您需要了解什么。
W3C 为何要定义 XML 1.1?
1998 年当 W3C 建立 XML 1.0 时,选择了 Unicode 2.0 作为定义的基础,这是当时 Unicode 标准的最新版本。Unicode 标准意味着为世界上每个字符提供一个唯一的数字--编码,这样所有字符都能被计算机表示并正确地处理。当然,为世界上的所有字符分配数字是一项耗时的任务。因此,Unicode Consortium 定义 Unicode 的标准体花费了数年时间;大约每隔一年他们就发布一个新的版本,每个版本都包括一组全新的字符。但是这意味着,依赖于 Unicode 标准的系统要么以向前兼容的方式设计,要么及时更新以适应新的版本。
不幸的是,XML 1.0 的设计不能很好地适应 Unicode 的新版本。尽管 Unicode 2.0 之外的字符也可以在 XML 1.0 文档中使用,但不能用于 XML 的重要成分,如元素名和属性名以及枚举属性值中。
原因在于,XML 1.0 的设计者选择把这些结构限制在当时已经定义(分配了数字)的字符范围之内。他们认为允许使用还没有分配给任何字符的编码是没有意义的,而且存在风险,这是完全可以理解的。但不幸的是,这也意味着一旦定义了新的字符,如果不改变 XML 的定义就无法使用这些新的字符。
随着 Unicode 后续版本的发布,缺乏对这些版本所提供的新字符的支持迫使 XML 不得不进行修订。这个问题,再加上已经发现的第一版中总会存在的少许瑕疵,诱使 W3C 授权它的 XML 核心工作组来定义新的版本。
XML 1.1 和 XML 1.0 的主要区别是什么?
着手研究 XML 1.1 的初期,XML 核心工作组讨论了这种可能性:仅仅把 XML 的基础由 Unicode 2.0 改为 Unicode 所提供的最新版本(当时是 3.0),在原有的结构上再加上新的字符。但是,这只能是一种暂时性的解决方案,Unicode 在发布几个版本之后,核心工作组又会陷入同样的困境。因此,他们考虑了一种更加根本的方法:向前兼容。
您无疑非常熟悉向后兼容:如果一个系统能够处理比它的开发目标更老的事物,则称它是向后兼容的。向前兼容是指能处理将来版本的能力。注意这两种性质不是互斥的--可以同时具有向后和向前兼容。
和 XML 1.0 不同,XML 1.1 是和 Unicode 标准向前兼容的。就是说,它的定义使得今天开发的 XML 1.1 处理程序,即使文档中包含只有在将来的 Unicode 标准中才会分配的字符,也仍然能够处理。
这是如何做到的呢?简单地说,在 XML 1.0 中,像元素名这样的构造明确规定了允许的特定字符,而排除了其他任何字符。这样就排除了还没有分配的任何字符。XML 1.1 采用了相反的方法:除了特定字符外,它允许任何可能的字符。这些字符通常是对于 XML 处理程序有特殊含义的字符,比如左尖括号(
< )或空格,以及可能造成问题的字符,如空字符。这种方法意味着,将来加入到 Unicode 中的字符实际上已经允许出现在元素名或者其他类似的构造中。
不过这种方法有一个很小的缺点。如果在 XML 1.1 文件中使用 Unicode 还没有分配的字符--即不对应任何实际的字符--XML 1.1 处理程序就会像它已经在 Unicode 中定义那样处理,甚至不会提出某种类型的警告。不过,最终的权衡是利大于弊,尤其是您事先不可能生成这样的字符,因为多数编辑工具根本不允许这样做。
其他区别
既然 XML 核心工作组要定义 XML 的新版本,合理的办法似乎是同时修正困扰 XML 1.0 的其他一些问题。首先是 XML 定义的行尾标记与 Unicode 不一致。这一点对 IBM 主机和 IBM 兼容主机,以及和它们通信的任何系统影响尤其明显。在这类主机上,工具使用 XML 1.0 不能识别的字符(NEL)标记行尾。这意味着,如果在这类系统上使用像记事本这样简单的工具创建一个 XML 1.0 文档,然后交给 XML 1.0 兼容的处理程序,文档就会因为不是结构良好的而被拒绝。XML 1.1 通过在标记行尾的字符列表中增加 NEL(
#x85 )而解决了这个问题。为了完整起见,该列表中还增加了 Unicode 行分隔符(
#x2028 )。
此外,XML 1.1 允许在文档中通过使用字符引用来包含控制字符。其中涉及到从
#x1 到
#x1F 的控制字符,其中多数在 XML 1.0 被禁止使用。这意味着现在的文档中可以包含铃声字符,比如:
#07 。但是,这些字符仍然不能直接出现在文档中,因为这样会违反 XML 所用的 MIME 类型(text/xml)的定义,那些期望 XML 文件中只含文本性字符并以特殊方式处理控制字符的工具可能会出现问题。
 |
在程序中支持 Unicode
在 Java 技术中,
String 类可以包含任何 Unicode 字符,因此对 Unicode 的字符基本上是完全免费获得的。但是,处理 Unicode 字符时 JDK 所提供的 API非常有限。因此,应该考虑使用 International Components for Unicode 或者 ICU(请参阅
参考资料),对于 C 和 C++ 开发人员也有类似的工具,它提供了一组支持 Unicode 和软件国际化与全球化的库。
|
|
最后,XML 1.1 还增加了字符规范化检查。尽管 Unicode 的初衷是为每个字符提供唯一的数字,但某些字符--或者用户认为是字符的东西--可能实际上有多种表示方式。比如,带有重音符的“e”(
rsum 中的
)通常用分配给该字符的单个编码(
#xE9 )表示,但也可表示为等价的多编码序列(
#x65 表示“e”,
#x301 表示重音符)。还有一些字符根本没有唯一的编码,比如带有变音符号的“c”(变音符号是“fa?ade”中“c”下面的标记)。相反,只能通过组合多个编码来表示(即
#xE9 “e”后跟
#x327 变音符号)。这是因为可能的组合数是无限的。如果有多种等价的表示,简单的字符串比较可能无法把等价的字符串看作是相同的。为了解决这个问题,Unicode 定义了几种方法在处理字符串之前进行规范化。XML 1.1 允许 XML 1.1 处理程序检查文档是否采用了规范形式,如果没有这种信息,应用程序的程序员可能需要执行规范化,以保证其代码不依赖于文本的特定形式。
XML 1.1 的问题在哪里?
那么为何您没有听说过 XML 1.1 呢?简单地说就是为了避免混乱。XML 的成功很大程度上归因于它的稳定性和普适性。您可以确信,任何兼容 XML 1.0 的处理程序都能够处理您的结构良好的 XML 1.0 数据。推出 XML 的新版本从根本上说就象是推出一种新的格式,导致工具被划分成两组,分别适用于 1.0 和 1.1。 尽管要求 XML 1.1 处理程序也支持 1.0(因此 1.0 和 1.1 都能够理解),大量现存 1.0 工具却不能应付 XML 1.1 文档。因此,谨慎地推出 XML 1.1 非常重要。为了解决这一问题,W3C 选择的办法是建议生成 XML 文档的应用程序尽可能继续使用 XML 1.0,只有在必要的时候才使用 XML 1.1。实际上,这意味着除非有不得已的理由就不要改变。这就是为何多数人至今还没有看到 XML 1.1 的原因。一些工具如 Xerces 已经支持 XML 1.1 有数月了,少数人注意到了这一点。这种策略使 XML 1.1 处理程序的部署不至于造成混乱,从而危害整个计算机行业。
但是在实践中 W3C 的建议很难实行。除非数据中附有这些信息,否则就很难发现。显然,直接生成 XML 1.1 文档更加简单。理想情况下,这一天不会太远了。
但即使现在,仍然需要考虑一种特殊的情况。您也许还记得前面提到的向前和向后兼容--非常不幸,XML 1.1 不能完全向后兼容 XML 1.0。实际上,有少量 XML 1.0 字符不允许在 XML 1.1 中出现,即从
#x7F 到
#x9F 的控制字符。为了改进字符编码检测的健壮性,这些字符现在只允许作为字符引用出现。对于一个允许有更多字符直接出现在 XML 文档中的版本而言,这似乎有点奇怪,但是人们认为实现编码检测带来的好处足以抵消这种不一致性,这种小小的不兼容性是完全值得的。而在实践中,这仍然意味着在生成 XML 1.1 文档时需要在数据中查找这些字符。
XML 1.0 和 1.1 文档之间共享外部实体
一旦人们开始生成 XML 1.1 文档,越来越多的人会希望在 1.0 和 1.1 文档之间共享外部实体。XML 的特点之一是允许内容的重用,它提供了一种方式把内容保存在一个文件中,然后在另一个文件中包括这些内容。这种 XML 片段称为
外部实体。XML 1.1 的引入提出了一个问题,即如何在 XML 1.1 文档包括 XML 1.0 实体的混合环境中处理这些内容。为了简化起见,XML 1.1 规范指出,实体根据使用它们的文档来处理。实际上,这意味着在新的 XML 1.1 文档中仍然能够使用过去的 XML 1.0 实体,不需要转换或者复制以标记为 XML 1.1。唯一可能出现的问题是,如果向 XML 1.0 实体中增加了只能用于 XML 1.1 的字符,处理程序不会检测到它,仍将作为 XML 1.1 输入处理。但是,只有当您再作为 XML 1.0 文档的一部分使用该实体时才会出现问题。
Namespaces 1.1 规范
W3C 发布 XML 1.1 Recommendation 的同时,也发布了相应的“Namespaces in XML 1.1”规范。所谓的 XML 名称空间的这个新版本在上一版本上增加了少许内容。之所以出现这个版本,是因为“Namespaces in XML 1.0”按照其定义的方式仅限于 XML 1.0,严格说来不能用于 XML 1.1。新的版本解决了这个问题。但并没有全部解决:新版本带来了一个值得注意的特性。为何允许不声明默认的名称空间,而不能不声明特定的名称空间前缀,这个问题可能已经困扰您很长时间了。最初的设计者相信这样做没有必要,但确实曾经令很多人苦恼过。它使得模型不够正规,并反映在 Infoset 中。新版本克服了这一缺陷,非常自然地把未声明的前缀和空名称空间联系在一起,如:
xmlns:foo="" 。
XML Infoset 规范也有 1.1 版吗?
XML 1.1 和 Namespaces 1.1 所作修改的性质不要求 Infoset 规范作相应的修改。W3C 在发布其他两个推荐标准的同时,也发布了 XML Information Set Recommendation 的一个新版本,描述了这些规范的影响,但基本上仅限于 Infoset 的内容。数据模型的结构没有变化,因此不需要定义新的信息项或者修改原来的信息项。这意味着,开发人员不必太担心这两个方面;如果能够在程序中处理 Unicode 字符,也应该能处理 XML 1.1 中引入的新字符,不需要作任何修改。
工作仍在继续
尽管 XML Infoset 规范不需要修改,不幸的是,并非所有的 XML 相关规范都是如此。比方说,XML Schema 规范就需要修订。比如,事实上
xml:string 类型是基于 XML 1.0 中所允许的字符定义的。因此,包含 XML 1.1 控制字符的字符串是不合法的。这就意味着实际上不能使用 XML Schema 验证 XML 1.1 文档。如果使用了仅能用于 XML 1.1 的字符,XML Schema 兼容的处理程序就会宣称这样的文档是无效的。虽然还不清楚如何解决这一问题,W3C 意识到了这一点并正在研究。
结束语
我希望本文能够揭开环绕着 XML 1.1 及其伴随规范 Namespaces 1.1 的神秘面纱。如果程序中要求支持,掌握了这些信息后您就可以准备处理 XML 1.1 了。XML 1.1 不是一次革命,仅仅是 XML 1.0 的
发展,不需要很大的变动。随着解析器的升级,多数人最终将使用 XML 1.1,就像 Xerces 的所有用户所做的那样。事实上,自从一年前推出 2.3.0 版之后,Xerces Java 就可以解析 XML 1.1 文档!而最近的 2.5.0 版之后,Xerces C++ 也可以解析 XML 1.1 文档。因此,如果选择了这些版本或者更新的版本,即使您可能不知道,但实际上您已经能处理 XML 1.1 文档了。
参考资料
关于作者  | |  | Arnaud Le Hors 是一位 IBM 资深软件工程师,从事与 IBM 的随需应变战略有关的软件标准工作。他代表 IBM 参与了
W3C 的不同工作组,比如 XML 核心工作组和 DOM 工作组,并参与了几种 W3C 规范的开发,其中包括 XML 1.1 和 Namespaces
in XML 1.1。 |
对本文的评价
|