级别: 初级 Kevin Williams (kevin@blueoxide.com), CEO, Blue Oxide Technologies,LLC
2002 年 7 月 01 日
在本专栏文章中,Kevin Williams 研究了 XSLT 2.0 的最新工作草案并提供了某些代码样本来展示 XML 样式语言的新版本是多么有用。
XSLT 2.0 添加了几个显著增强样式表处理数据能力的特性。除了构建在 XPath 2.0(我将在下个月的专栏文章中讨论它)上的优势之外,XSLT 2.0 向 XSLT 语言提供了许多其它优势,包括下列能力:
- 分组节点
- 创建用户定义的函数
- 从单个样式表创建多个结果文档
让我们详细研究这些特性的每一个:
分组节点
XSLT 1.0 中最令人头痛的问题之一是该语言不能直接对一组节点执行
SELECT DISTINCT 。这种能力非常有价值,例如,当您想将带有书籍作者的书籍列表(如
清单 1所示)转换成显示作者及其所有书籍的对应文档(如
清单 2所示)。
清单 1. 带有作者姓名的书籍
<book title="Professional XML">
<author name="Kevin Williams" />
<author name="A. Nother Author" />
</book>
<book title="XML Antipatterns">
<author name="Kevin Williams" />
</book>
<book title="XML for Managers">
<author name="A. Nother Author" />
<author name="Y. A. Author" />
</book>
|
清单 2. 带有书名的作者
<author name="A. Nother Author">
<book title="Professional XML" />
<book title="XML for Managers" />
</author>
<author name="Kevin Williams">
<book title="Professional XML" />
<book title="XML Antipatterns"/>
</author>
<author name="Y.A. Author">
<book title="XML for Managers" />
</author>
|
虽然用 XSLT 1.0 可能完成这个转换,但却是棘手和难以使用的:您必须选择所有作者节点,按姓名对它们排序,然后使用
xsl:if 块来确定正在处理的作者是否与集合中前一个节点同名。对于发现的每个作者,代码必须接着反过来到树上全面搜索以获取嵌入特定作者姓名的所有书籍元素。它有效,但很笨拙。
在 XSLT 2.0 中引入了
xsl:for-each-group 元素。这个元素允许程序员获取一组节点,按某些标准来进行分组,然后处理由那一选择过程组成的每一个组。这使得执行转换更简单,如下面的
清单 3所示。
清单 3. xsl:for-each-group 元素的示例
<xsl:for-each-group
select="book/author"
group-by="author/@name">
<xsl:sort select="author/@name">
<author name="{current-group()/@name}">
<xsl:for-each select="current-group()">
<book title="{../@title}" />
</xsl:for-each>
</author>
</xsl:for-each-group>
|
创建用户定义的函数
XSLT 2.0 还包含新的
xsl:function 元素。这个元素允许您定义一个与用任何其它编程语言编写的函数操作很相似的函数:您定义一个强类型输入和强类型输出,并且操作输入以产生输出。当您在
namespace (通常是与样式表关联的
namespace )中声明函数后,接下来可以在您调用内置 XSLT 函数的任何地方(例如,在
xsl:value-of 元素的
select 属性中)调用它。这个功能作为递归应用程序工作良好,如
清单 4中的样本阶乘函数所示。
清单 4. 使用 xsl:function 的阶乘函数
<xsl:function name="local:factorial">
<xsl:param name="value" type="xsd:integer" />
<xsl:result
select="if($value=1)
then 1
else $value * local:factorial($value - 1)" />
</xsl:function>
|
从单个样式表创建多个结果文档
在 XSLT 1.0 中,转换总是产生一个输出文档。使用 XSLT 2.0,您可以从单个样式表创建多个结果文档。例如,您可以创建框架式 XHTML 文档所有框架或相同内容的不同格式(例如,具有创建同一来源的 HTML、XHTML、WML 和 VoiceML 解释的单个样式表)。每个由转换创建的附加文档都具有一个与其关联的 URI。URI 的使用是特定于应用程序的(例如,它可能用于将辅助文档序列化到文件系统的特定位置或者只是作为使用 XSLT 处理器通过代码访问辅助文档的一种软件机制)。
清单 5显示了如何创建主文档以及两个辅助文档。
清单 5. 用于生成附加文档的 XSLT 2.0 代码
<xsl:template match="/">
... primary output generation here ...
<xsd:result-document href="result.wml">
... generation of WML output here...
</xsd:result-document>
<xsd:result-document href="result.voiceml">
... generation of VoiceML output here...
</xsd:result-document>
</xsl:template>
|
XHTML 支持
XSLT 2.0 的一个很重要的特性是您可以指定将特定转换的输出序列化成 XHTML 格式。该序列化采用几个特殊步骤来确保输出与当前浏览器兼容。具体地说:
- 空元素在其空标记(/>)符号前有一个空格
- 带有空内容模型的元素总是使用空标记缩写(<br />)
- 没有空内容模型但正好为空的元素从不使用空标记缩写(<p></p> 而不是 <p />)
- 正确转义属性中的非 ASCII 值
在 XPath 表达式中排序
使用 XSLT 2.0,您还可以创建命名的排序规范。然后,您可以在 XPath 表达式中使用这些规范来对数据进行排序。这使得在 XPath 表达式中的任何级别上对任意节点集合进行排序成为可能。例如,
清单 6首先按书名,然后按作者姓名对
清单 1中样本 XML 文档的书籍列表进行了排序。
清单 6. 使用 sort XPath 函数
<xsl:sort-key name="bookSort">
<xsl:sort select="@title" />
<xsl:sort select="author/@name" />
</xsl:sort>
<xsl:for-each select="sort('bookSort', book)">
... each book is processed, ordered by title and author name...
</xsl:for-each>
|
结束语
在本专栏文章中,我已经研究了对 XSLT 2.0 进行的一些重要更改。从 XPath 的版本 1.0 到版本 2.0 也有重要更改,这些我将在下一篇专栏文章中处理。由于 XSLT 2.0 仍是工作草案形式,可能直到将它提升到提议的建议书(Proposed Recommendation)状态后,它才可能具有一个稳定的实现。然而,如果您现在就弄清了新特性,则当 XSLT 2.0 可用时,您就可以利用它设计您的系统。
参考资料
关于作者
对本文的评价
|