级别: 初级 Kevin Williams (kevin@blueoxide.com), CTO, Blue Oxide Technologies,LLC
2003 年 1 月 01 日
Kevin Williams 研究了 XPath 2.0 规范的最新状态,并且提供了一些 XPath 2.0 特性的特定示例,这些特性会使 XML 开发人员的工作更加轻松。示例是用 XML 和 XPath 的形式提供的。
XSLT 1.0 和 XPath 1.0 最初是打算为 XML 文档提供简单的样式语言支持,主要是将这些文档转换成 HTML 以呈现在浏览器中。但是,自从 XSLT 和 XPath 可以使用之后,它们就被强行用于各种任务中,而这些任务 ― 从 XML 文档中复杂的数据操作(聚合、单值选择和关系旋转)到一种 XML 形式向另一种形式的 XSLT 转换 ― 并不是它们的设计初衷。在这些规范的版本 2.0 中,W3C 试图使 XSLT 和 XPath 更加灵活和健壮,以便于处理这些技术的新用法。
在上一篇专栏文章中,我研究了 XSLT 的一些新特性。在本篇专栏文章中,我只研究 XPath2.0 的几个要点 ― 由于要点太多,因而无法在一篇专栏文章中全部研究。
对于本专栏而言,特定前缀的映射含义如下:
-
xf: 前缀被认为映射到 XPath 2.0 函数名称空间(http://www.w3.org/2002/08/xquery-functions)。
-
xsl: 前缀映射到 XSLT 2.0 名称空间。
-
xs: 前缀映射到 XML 模式名称空间。
xf:distinct-values 函数
在使用 XSLT 1.0 样式表时,开发人员面临的最重大的挑战之一就是编写与 SQL 中 SELECT DISTINCT 等同功能的 XML 代码 ― 即一个获取节点集并返回那些节点唯一值列表的表达式。在 XSLT 1.0 和 XPath 1.0 中这不是不可能实现的,但都是极其困难的。基本上,您都必须写一条
xsl:for-each 语句以特殊的排序顺序对每个节点求值,然后不断回头查看节点列表,以了解是否所有匹配特定值的任何其它节点都被处理了。有了 XSLT 2.0 ,以及引入了
xf:distinct-values 函数,这个问题就迎刃而解了。下面
清单 1中是一个 XML 文档的快速示例:
清单 1. 带有作者姓名的 books
<books>
<book author="Kevin Williams" title="Professional XML 2.0" />
<book author="Lewis Carroll" title="Alice in Wonderland" />
<book author="Lewis Carroll" title="Through the Looking-Glass" />
</books>
|
假定您想要标准化输出作者信息,并创建一个类似
清单 2的文档:
清单 2. 带有书名的 authors
<authors>
<author name="Kevin Williams">
<book title="Professional XML 2.0" />
</author>
<author name="Lewis Carroll">
<book title="Alice in Wonderland" />
<book title="Through the Looking-Glass" />
</author>
</authors>
|
要做到这一点,使用 XPath 和 XSLT 1.0 时,需要做类似于
清单 3的工作:
清单 3. XPath 1.0 中的 SELECT DISTINCT
<xsl:template match="books">
<authors>
<xsl:for-each select="book">
<xsl:sort select="@author" />
<xsl:variable name="thisAuthor">
<xsl:value-of select="@author" />
</xsl:variable>
<xsl:if test="count(preceding-sibling::book)=0">
<author name="{$thisAuthor}">
<xsl:for-each select="../book[@author=$thisAuthor]">
<book title="{@title}" />
</xsl:for-each>
</author>
</xsl:if>
<xsl:if test="preceding-sibling::book[1]/@author != $thisAuthor">
<author name="{$thisAuthor}">
<xsl:for-each select="../book[@author=$thisAuthor]">
<book title="{@title}" />
</xsl:for-each>
</author>
</xsl:if>
</xsl:for-each>
</authors>
</xsl:template>
|
记录文档的过程稍微有点凌乱和困难,但是使用
xf:distinct ,这会变的很容易,如
清单 4所示:
清单 4. XPath 2.0 中的 xf:distinct
<xsl:template match="books">
<authors>
<xsl:for-each select="xf:distinct(book/@author)">
<xsl:variable name="thisAuthor"><xsl:value-of select=".">
<author name="{$thisAuthor}">
<xsl:for-each select="book[@author=$thisAuthor]">
<book title="{@title}" />
</xsl:for-each>
</author>
</xsl:for-each>
</authors>
</xsl:template>
|
这与
xsl:for-each-group 有什么区别呢?任何实现 XPath 的地方都可以使用
xf:distinct ― 因此,它可以作为 XQuery 1.0 的一部分及专门的 XPath 处理器使用。利用
xf:distinct ,可以在值集合上执行其它操作,这与
xsl:for-each-group 相反,后者强制对不同的值单独进行操作。
这一变化解决了 XSLT 作者在试图样式化文档时遇到的许多问题。XSLT 还有许多其它变化,样式表程序员会发现它们非常有用。
xf:document 函数
在 XSLT 1.0 中使用多个文档是有问题的。XPath 2.0 的设计人员明智地选择了通过
xf:document 机制来包括额外的文档处理能力。该函数允许从 URL 装入一个或多个文档,并进行处理。例如,假定您在资源库中拥有
清单 5、6 和 7中所示的文档类型:
清单 5. 样本零件文档 1
<part name="Grommets" size="3 in." color="blue" />
|
清单 6. 样本零件文档 2
<part name="Grommets" size="3 in." color="blue" />
|
清单 7. 样本零件文档 3
<part name="Grommets" size="3 in." color="blue" />
|
假定您现在在一个目录中有 500 个这样的文档,您希望创建您所拥有的所有蓝色零件的列表。无需利用中间层语言(如 Java)编写代码以装入所有这些文档并查找颜色为蓝色的零件,可以编写一个列出在哪可以找到所有零件的索引(请参阅
清单 8):
清单 8. 零件索引文档
<parts>
<part file="part1.doc" />
<part file="part2.doc" />
<part file="part3.doc" />
</parts>
|
您可以编写一个为您完成这项工作的样式表,其代码片段类似于
清单 9:
清单 9. 用于跨文档的 xf:document
<xsl:template match="parts">
<blueParts>
<xsl:for-each select="xf:document(part/@file)/@color='blue'">
<part name={@name} size={@size} color={@color} />
</xsl:for-each>
</blueParts>
</xsl:template>
|
这种技术特别适用于分布式网络的内容,在分布式网络中,零件信息可以放在一台服务器上,而客户信息可以放在另一台服务器上。通过利用样式表(使用
xf:document 从其它 URL“拉”信息),允许该数据可以在创建它的地方起作用。
xf:current-dateTime 函数
将样式表应用于 XML 文档时,在输出中包含已转换结果的创建日期通常都很有用。当创建 HTML 文档以驱动用户界面时,这特别重要;此类信息可以帮助高速缓存系统知道什么时候信息的副本失效了。使用 XPath 2.0 中的
xf:current-dateTime 函数可以获得当前日期和时间(请参阅
清单 10):
清单 10. xf:current-dateTime 示例
<xsl:value-of select="xf:current-dateTime()" />
|
这可能会返回
清单 11中所示的字符串:
清单 11. xf:current-dateTime 样本结果
然后,可以“按现状”使用该字符串,或者将其转换成不同的日期格式,以便于在生成的文档中使用。
更佳的 XML 模式兼容性
因为 XPath 2.0 目前在 XSLT 2.0 和 XQuery 1.0 之间共享,因此,XPath 需要更健壮的 XML 模式支持。实际上,XPath 2.0 中的整个数据模型目前都是强类型的:而不是简单的字符串、数字和布尔类型,值目前使用了作为 XML 模式规范一部分定义的原语。提供了完整的函数集,因此可以把这些值显式地从一种类型转换为另一种类型,将这种转换作为它们在 XPath 2.0 中操作的一部分。例如,通过使用类型名称可以将一个值强制转换为另一种类型,就象是一个函数一样。因此,使用
清单 12中的代码片段,可以将值强制转换为无符号整数:
清单 12. XML 模式类型强制转换示例
XPath 2.0 中的强类型确保由 XSLT 样式表创建的文档能够依据强类型的 XML 模式进行验证。在 XSLT 2.0 之前,没有方法可以保证这一点(例如,保证数字是无符号整数)― 为了确保样式表不提供错误值,XML 模式验证步骤是必需的。
在本文中,我只是略微谈及了 XPath 2.0 必须提供的一些要点。虽然距离这项技术提升为建议书状态还有一段时日(至少 6 个月),但是,熟悉 XPath 2.0 的特性和功能将有助于您在开始实现时能够充分利用它。
参考资料
关于作者
对本文的评价
|