在本文,您将采用使用纯 XSLT 实现的函数库,它使应用程序可以利用只在模式感知处理器中可用的与 XPath 2 模式有关的节点测试。您还会看到如何将验证过程从实例数据处理中分离出来。您可以将 XSLT 函数库和任何基础 XSLT 2 处理器一起使用,利用模式信息处理实例数据 —— 这个方法也可用于 XQuery 应用程序。
XPath 2 引入了一些新的序列类型构造,允许应用程序在 XML 模式中使用类型定义和元素声明,从而在 XML 实例文档中匹配元素。在应用程序中使用这些构造可以减少代码的复杂性,并且提高了应用程序的通用性。
不幸的是,目前这些构造只能用于模式感知的 XPath 主机语言处理器,比如模式感知的 XSLT 或 XQuery 处理器,并且这些模式感知处理器经常紧密耦合验证过程和实例数据处理过程。这意味着应用程序必须执行验证过程才能使用模式信息,而不管是否有必要这样做(实际上在很多情况下,实例数据到达实例数据处理器之前,已经针对某个特定模式进行了验证 —— 因此没有必要再执行验证过程)。在这些场景中,处理实例数据需要用到的是模式信息,而不是验证。
|
在本文中,我将介绍用纯 XSLT 实现的函数库,它使应用程序可以从新的 XPath 2 构造获得益处;同时,它将把验证过程从实例数据处理过程中分离。您可以将函数库和任何基础 XSLT 处理器一起使用,利用模式信息处理实例数据,而不需经过不必要的验证过程;这个方法也可用于 XQuery 应用程序。
在 XPath 2 中,可以在一个 XPath 表达式中使用两种与模式有关的节点测试,以根据模式类型定义和元素声明选择元素节点。这两种构造的基本语法是:
element(ElementNameOrWildCard, TypeName)
。schema-element(ElementName)
。
其中,ElementName
表示实例文档中的元素的限定名;ElementNameOrWildCard
是一个元素名或 “*”;而 TypeName
表示 XML 模式文档中的类型定义的限定名。
一般而言,带有类型名的构造 element()
匹配类型定义直接或间接来自特定类型的元素。构造 schema-element()
匹配在构造指定的头元素的替代组中声明的元素。
例如,
element(Person, PersonType)
匹配名为Person
、类型为PersonType
的元素。Element(*, PersonType)
匹配一个元素节点,该节点的类型必须是PersonType
,或者直接或间接来自PersonType
,而不考虑其名称。schema-element(Person)
匹配一个元素节点,该节点必须在以Person
开头的代替组中声明。
详细的节点测试语法和语义参见 参考资料 中的 XPath 2 规范。
与简单地基于实例文档的程序相比,充分利用与模式相关的节点测试的程序可以获得简单性、通用性 和扩展性 等优点:
- 简单性:程序可以使用这些节点测试,选择基于共同组 head 元素或类型定义的一组元素,而不是逐一列举所有具体的元素名。
- 通用性:程序设计可以基于模式定义,从而使程序可以处理遵循某一模式的一类文件。
- 扩展性:可以轻松修改在节点测试范围内新添加的元素,只需添加新的处理代码,而不必更改现有的代码。
这三个特性提高了生产率。我将在本文后面进一步展示这些优点。
虽然与模式相关的节点测试具有以上这些优点,但是它们不能用于大部分 XSLT 或 XQuery 处理器,因为大部分处理器只提供基本功能,不支持 XML 模式。另外,虽然高级模式感知处理器确实支持这些节点测试,但它们的数量很少,并且在实际操作中常常耦合了验证过程和数据处理过程。
换句话说,使用这些处理器需要重复地执行验证过程,这样才能在程序中使用模式信息,即使已经知道文档对于这个模式是有效的。此外,您只能静态地加载应用程序使用的模式文档;程序不允许动态地加载和使用模式。
解决这些问题需要采取其他方式,将模式信息公开给应用程序,并允许它们不需要经过验证就能利用模式信息。这正是我在本文介绍的函数库的驱动力。
函数库实际上提供一些函数,它们通过给定的实例元素、模式类型定义和模式元素声明执行节点测试。函数库包含以下三种类型的函数:
- 加载模式文档
- 执行模式测试
- 在模式文档中定位类型定义或元素声明
看看这些函数是如何实现的。
函数库提供一个函数 load-schemas-by-URI()
。load-schemas-by-URI()
函数使用 XPath doc()
函数读取和解析位于特定 URI 的模式文档。它返回文档节点的序列,包含由 URI 指定的主模式文档和所有由主模式导入或包含的模式文档。
如清单 1 所示,实际上模式加载过程只涉及两个步骤。
清单 1. 通过 URI 加载模式
<xsl:function name="xsdf:load-schemas-by-URI" as="document-node()*"> |
一个步骤是加载所有引用的模式。这通过像清单 2 一样递归地调用函数 load-referenced-schemas()
来执行。
清单 2. 加载引用模式
本文转自IBM Developerworks中国