本专栏目前的主题是语义透明性:正确解释 XML 文档内容的能力。语义透明性可能是 XML 建模最重要的方面。这是一系列文章中的第一篇,我们将考察语义透明性的很多不同方法,讨论它们对使用 XML 的开发人员来说意味着什么。
这是 Thinking XML 专栏的第 30 期。从第一篇文章至今差不多有四个年头了,回想一下,时间的飞逝和事情的发展真是令人吃惊。与 XML 有关的活动非常之多,我希望有些已经在本专栏的主题中出现过了。这些活动和 XML 在知识管理技术中的应用特别密切,这也是本专栏所关注的焦点。2001 年 2 月份发表的第一期文章中讨论了语义透明性的目标,我认为这是 XML 数据建模最重要的方面。本专栏中已经考察了实现语义透明的不同方法。我将通过几篇文章介绍关于语义透明性的一些有趣的方法和技术,阐明我对这一领域进展的看法,本文是第 1 部分。这一系列的文章由三部分组成:在正式的模式中使用非正式的描述(本文)。 对于自上而下的语义透明性使用模式标准。 对于自下而上的语义透明性在模式中使用语义锚(anchor)。
正式的模式,非正式的透明性
对于 XML 最常见的一种误解是,认为只要定义了模式,别人就会知道如何处理 XML 实例,如何与您的系统交互。有可能这样,但这要看模式是如何编辑的,一般来说,这不是由于模式语言本身的特性造成的。清单 1 是一个示例 RELAX NG 模式(紧凑语法)的片段:
清单 1. 使用注释提供语义线索的 RELAX NG 模式
namespace dc = "http://purl.org/dc/elements/1.1/"element purchase-order{
dc:description [ "General purpose purchase order for merchandise" ]
attribute id {
dc:description [ "Unique identifier for the purchase order" ]
text
}
#The rest of the schema here}
如果不熟悉 RELAX NG,上面的第一行是 Dublin Core 的名称空间声明,这是一种非常流行的词汇表,用于诸如标题、描述、性质和其他类似库的元数据元素。第二行定义了一个名为 purchase-order 的元素。以 dc:description 开始的行是一个注释,使用了前面声明的名称空间前缀,指出注释的内容将提供符合 Dublin Core 描述元素的信息。后面的 4 行定义了一个名为 id 的属性,其值是普通文本。这个属性定义有自己的注释,指出了该属性的意义。最后一行是一个评注。注意,该例中使用注释提供了帮助理解这个模式语义的重要信息,而用评注传达附带的信息。<purchase-order id="123"/> 就是符合该模式的文档。
如果清单 1 是 Acme Organization 采用的订单模式,那么独立的 Zenith Organization 也许会采用清单 2 所示的模式。
清单 2. 和清单 1 类似的 RELAX NG 模式
namespace dc = "http://purl.org/dc/elements/1.1/"element po{
dc:description [ "Simple purchase order" ]
attribute number {
dc:description [ "Number for identifying the purchase order" ]
text
}
#The rest of the schema here}
注意,其中的注释是类似的,而具体的元素和属性名却不同。相应的文档可能是 <po number="123"/>。看过上面两个模式的人可以从注释中发现:一个文档中的 purchase-order 元素与另一个文档中的 po 元素是等价的,而 id 属性和 number 属性也是等价的。这样就通过非正式的方式得到了语义透明性。人们必须使用不严密的自然语言技巧来理解注释,而不是使用某种严格的、没有歧义的定义。
问题在于这个过程没有可伸缩性。在上面的例子中,两个词汇表的数据元素之间存在简单的一对一映射,即使不经意地阅读这些注释,也很容易对它们作出比较。实际的情况中常常涉及更复杂的模式,映射关系不那么容易预测,注释和其他非正式描述中也存在细微的差别。这种情况下,通过自然语言的模式注释来获得语义透明性可能非常困难。
DTD 没有直接提供注释,但其他流行的模式语言提供了注释,如 RELAX NG、W3C XML Schema (WXS) 和 Schematron。这些语言中可以构造供机器识别的注释,为语义透明性提供更可靠的方法。后面的文章中将介绍一些这方面的技术。不幸的是,这种技术没有经过很好的讲解、讨论,甚至分析,部分原因在于研究 XML 的人们错误地认为语义透明性并不是一个紧迫的问题,或者认为 XML 本身已经具备了语义透明性。从我的观点来看,有一件特殊的事情分散了人们对语义透明性的注意。
非凡的障眼法
XML 专家认识到了用上述这种非正式描述提供语义透明性的弱点。随着 XML 1.0 获得成功,增加这类设施的尝试一直是接下来 要讨论的问题之一,其他要讨论的问题包括链接、处理惯例,等等。最初,尝试解决这些问题的人们划分成不同的阵营。最突出的一个阵营是那些熟悉主流编程语言和数据库管理系统的老手,他们认为形式化 XML 文档基础的最佳方式就是常见的数据类型化技术,这是他们最熟悉的。他们习惯于按照组成主流源和数据库系统静态数据类型化的最初设想来思考所有的语义。他们认为,只要将 XML 紧紧绑定到他们熟悉的隐喻上,就能够解决建模问题。
数据类型化的支持者可能把清单 2 中的模式修改成清单 3 所示的版本。
清单 3. 使用 WXS 数据类型的 RELAX NG 模式
namespace dc = "http://purl.org/dc/elements/1.1/"element po{
dc:description [ "Simple purchase order" ]
attribute number {
dc:description [ "Number for identifying the purchase order" ]
xsd:int
}
#The rest of the schema here}
这一次,WXS 数据类型被指定给了该属性,这反映出模式的设计人员认为订单号应该限制为一个整数。这就是 xsd:int 这一行的含义。显然增加的信息与模式的正确解释没有多少关系。客观地说,即使数据类型化的鼓吹者也不认为达到了目标,但是他们宣称增加的这一点精确性,使处理工具能够对 XML 实例作其他某种形式的推理和分析。我怀疑这种声明的可信性,但相信它花费了 XML 社区的很多精力,让该社区成员致力于不会有结果的数据类型妄想。这些精力本来可以在语义透明性问题上发挥更大的作用。
更直接的问题是,当人们反射性地使用数据类型时,常常以无法预料的方式降低灵活性。比方说,如果使用清单 3 所示模式的 Zenith Organization 希望和使用清单 1 所示模式的 Acme Organization 交易,那么现在问题进一步复杂化了,因为一个模式将 PO 看作整数,而另一个则将其视为普通文本。这种错误匹配反映在很多数据类型感知的工具中。匹配错误在任何集成项目中都是不可避免的,但是在这种情况下,严格数据类型化所带来的好处还抵不上灵活性方面的损失。
这对开发人员意味着什么呢?我并不是说不应该使用模式数据类型,但不要作为一种反射行为来使用。可以用它们标记经过深思熟虑的、在系统的整个生存期中都是合理的约束。不要被数据类型化先入为主,以致于忘记考虑如何澄清与 XML 词汇表有关的更一般的语义。
我在 Amara XML 工具箱中增加了根据 XML 节点中的文本范式推断数据类型的功能,这是为 Python 编程语言开发的一种 XML 处理库。我谨慎地将这种类型推断设成可选的功能,认为如果将其作为所有处理工具链条的基础可能是危险的。我还通过某种声明性的方法,使用户能够使用 Jeni Tennison 的 Data Type Library Language(DTLL,请参阅参考资料)自定义数据类型。 DTLL 帮助进一步明确了这一事实,即 XML 中的数据类型化只不过是对文本的一种特殊解释。这就是问题的症结所在:XML 是文本,而且只是文本。其他层次如数据类型化只不过是对文本的解释(而且是可选的解释)。如果没有看到这一点,就会陷入各种没有预料到的麻烦之中。
结束语
无论能否带来语义透明性,为模式编写良好的注释都非常重要。对于维护单独的数据词典文档,像数据库管理员所熟悉的那样,甚至注释就足够用了。对于模式中使用的每个项,数据词典提供的描述非正式地填充了这些项的语义。一旦认识到文本在 XML 中至高无上的地位,语义透明性的重要性就很清楚了。因为所有 XML 处理都归结为解释语言的问题,最重要的是找到一种方法减少解释的歧义性。如果您对模式、模式注释、数据类型化或者相关主题有什么想法,请提交到 Thinking XML 讨论论坛 和我们分享。