XSLT 2.0 和 XPath 2.0 的新特性

SLT 2.0 与 XPath 2.0 携手并肩。之所以将它们分开描述,是因为 XPath 2.0 也可用于XSLT之外的环境,比如XQuery 1.0。但是对于XSLT用户来说,它们是互相关联的。你不能在XSLT 1.0 中使用 XPath 2.0,或者在 XSLT 2.0 中使用 XPath 1.0。(至少到目前为止,W3C还没有这种组合的提议。)

你也许会问:XSLT 1.1 发生了什么?XSLT 1.1 已经取消了。官方的说法是在2001年8月,实际上在几个月前,XSLT工作组中止了XSLT 1.1,集中力量开发XSLT和XPath 2.0,将XSLT 1.1 的前期要求转到XSLT 2.0。

欢迎到来

许多的XSLT用户在很大程度上参与了新版XSLT的制订过程。就像许多语言的第一版一样,不经过实践的检验,这个语言的哪些扩展被证明是最重要的往往不很清楚。自从1999年11月16日XSLT 1.0 成了推荐标准以后,显然在某些方面缺少的功能应当在下一个版本中包括进来,本文我们将从下面四个方面看看XSLT 2.0:

  • 从结果树片断(result tree fragments)到节点集(node-sets)的转化
  • 有多个输出的文档
  • 对分组的内在支持
  • 用户定义函数(以XSLT实现)

RTF的末日

在XSLT 1.0 中结果树片断(Result Tree Fragment,RTF)类型很像节点集,实际上却是个二等公民。当你使用xsl:variable构建一个临时树的时候,得到的就是RTF。问题是你不能使用XPath表达式访问这个树的内容,除非你使用一个供应商提供的扩展函数,通常是node-set()之类,来把这个RTF转化成一类节点集(含有一个根节点)。这种RTF数据类型的存在本来是为了减少实现时的限制,但由于几乎所有的XSLT处理器都提供诸如node-set()之类的扩展函数,这种考虑显得有些不切实际。不管怎样,突破这种限制的呼声总会越来越明显,因为把复杂的变换分解成一系列简单的变换非常重要。

不知道你有没有猜出来,XSLT 2.0 为RTF打开了这个门。现在当你使用xsl:variable创建一个临时树,这个变量的值就是个真正的节点集。事实上,用XPath 2.0 的术语来讲,它是个真正的节点序列(true node sequence),包含一个 document node (这是一个XPath 2.0 的名称,也就是XPath 1.0 的"root node")。在这个序列上你可以使用XPath表达式深入到这棵树,对它应用模板(template)等等,就像使用其它源文件一样。有了XLST 2.0 就不再需要node-set()之类的扩展函数。

允许多个输出文档

许多XSLT 1.0 处理器所提供的另一个扩展就是多个输出文档,这种扩展被证明非常有用,对具有多个页面的网站的静态生成尤其如此。问题在于这个扩展功能不是标准的。每个处理器完成这种扩展的元素都不一样,例如 saxon:output, xt:document等等。

XSLT 2.0 使用 xsl:result-document元素提供了多个输出文档的一个标准方法。下面的样式表例子构建了多个输出文档,一个“主要结果文件”和几个“次级结果文件”。主要结果文件以XHTML存储,次级结果文件以纯文本方式存储。

<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns="http://www.w3.org/1999/xhtml">
  <xsl:output method="xhtml"/>
  <xsl:output method="text" name="textFormat"/>
  <xsl:template match="/">
    <html>
      <head>
        <title>Links to text documents</title>
      </head>
      <body>
        <p>Here is a list of links to text files:</p>
        <ul>
          <xsl:apply-templates select="//textBlob"/>
        </ul>
      </body>
    </html>
  </xsl:template>
  <xsl:template match="textBlob">
    <xsl:variable name="uri" select="concat(‘text‘, position(), ‘.txt‘)"/>
    <li>
      <a href="{$uri}">
        <xsl:value-of select="$uri"/>
      </a>
    </li>
    <xsl:result-document href="{$uri}" format="textFormat">
      <xsl:value-of select="."/>
    </xsl:result-document>
  </xsl:template>
</xsl:stylesheet>

xsl:document href 属性用来为相应的输出文件指定一个URI。对于许多处理器来说,这意味着以该文件名存储文件。而format属性用来引用一个已命名的指定输出。在这里,它指向以textFormat命名的xsl:output元素。

上例中的XHTML输出方式也是在XSLT 2.0中新引入的,这里勿须赘言。

简化的分组

XSLT 1.0 没有对分组的内在支持。特定的分组问题无疑可使用各种技巧解决,例如Muenchian方法,但是这种解决方法相当复杂难懂。对XSLT 2.0 的要求之一就是必须要简化分组,就像我们在下例中所看到的,这种方法能满足要求。

出现在 Requirements document 和XSLT 2.0 工作草案的这个例子是关于把下面简单XML文档中的城市列表,

<cities>
  <city name="milan"  country="italy"   pop="5"/>
  <city name="paris"  country="france"  pop="7"/>
  <city name="munich" country="germany" pop="4"/>
  <city name="lyon"   country="france"  pop="2"/>
  <city name="venice" country="italy"   pop="1"/>
</cities>

转换为如下所示的以国家进行分组的HTML表格:

<table>
   <tr>
      <th>Country</th>
      <th>City List</th>
      <th>Population</th>
   </tr>
   <tr>
      <td>italy</td>
      <td>milan, venice</td>
      <td>6</td>
   </tr>
   <tr>
      <td>france</td>
      <td>paris, lyon</td>
      <td>9</td>
   </tr>
   <tr>
      <td>germany</td>
      <td>munich</td>
      <td>4</td>
   </tr>
</table>

这种转换的难点在于生成最后三行(如粗体所示)。下面是XSLT1.0的一种解决方案:

  <xsl:for-each select="cities/city[not(@country =
                           preceding::*/@country)]">
    <tr>
      <td><xsl:value-of select="@country"/></td>
      <td>
        <xsl:for-each select="../city[@country = current()/@country]">
          <xsl:value-of select="@name"/>
          <xsl:if test="position() != last()">, </xsl:if>
        </xsl:for-each>
      </td>
      <td><xsl:value-of select="sum(../city[@country =
                 current()/@country]/@pop)"/></td>
    </tr>
  </xsl:for-each>

在上例中,对每个特定的国家,我们首先要用下面的XPath表达式找出它的第一个城市:

cities/city[not(@country = preceding::*/@country)]

然后,对每个分组,为了获得每个国家的城市名字列表以及该国的总人口,我们需要再回头引用该组的所有其他成员,这两种情况我们不得不作一些额外的工作,因为只能用下面的表达式才能引用到当前的分组:

../city[@country = current()/@country]

显然这不是个理想的局面,因为这种额外的代码往往是错误之源。 使用 xsl:for-each-group, XSLT 2.0 为你的大多数分组问题提供了答案。下面就是XSLT2.0对这个问题的解决办法(粗体表示新特性):

  <xsl:for-each-group select="cities/city" group-by="@country">
    <tr>
      <td><xsl:value-of select="@country"/></td>
      <td>
        <xsl:value-of select="current-group()/@name" separator=", "/>
      </td>
      <td><xsl:value-of select="sum(current-group()/@pop)"/></td>
    </tr>
  </xsl:for-each-group>

在上例中,xsl:for-each-group 作为XPath的取值上下文的一部分,对"current group"进行初始化,当前的分组是一个简单序列。一旦我们使用group-by属性设置好分组,以后就可以使用current-group()函数引用当前的分组。这就完全消除了XSLT1.0方案中的额外开销。

注意xsl:value-of中的separator属性。这个属性的存在是为了告诉处理器不只是要输出这个序列中的第一个元素的string值(XSLT1.0是如此作的),而是要按顺序输出该序列中所有元素的值。separator属性的取值为一个可选的字符串,用作输出中每个字符串的分隔符。为了与XSLT1.0兼容,如果没有指定separator属性,只输出该序列中的一个成员的值。

最后,根据xsl:for-each-group的三个属性的取值,可以解决不同的分组问题:group-by(如上面所示),goup-adjacent(用于根据文当中的节点顺序的相邻关系进行分组,例如将inline的<para>元素转化为块级(block)的<para>元素),以及group-start-with(根据序列中元素的模式(patterns)分组)。这些方法的例子可以在最新的XSLT2.0工作草案的"13.3 Examples of Grouping"中找到。

用户定义函数

XSLT2.0引入了一个新特性,就是允许定义他们自己的函数,并可以在Xpath表达式中使用。这是个非常强大的功能,无疑是非常有用的。样式函数(Stylesheet functions)是用xsl:function元素定义的。这个元素必须指定一个name属性。它包含0个或多个xsl:param元素,然后是0个或多个xsl:variable元素,后面是唯一的xsl:result元素。这种严格的内容模型看起来是个限制,但是你会发现XSLT2.0的真正强大之处就在于可定义xsl:result元素的select属性。你可能会想到,XPath2.0具备有条件表达式(if...then)和迭代(iterative)(列举?)表达式(for...return)。

就像下面例子(直接取于最新的工作草案)所示,许多工作是在xsl:resultselect属性中完成的。这个样式表调用了用户自定义的一个递归函数str:reverse()来输出字符串"MAN BITES DOG"。

<xsl:transform
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:str="http://user.com/namespace"
  version="2.0"
  exclude-result-prefixes="str">
<xsl:function name="str:reverse">
  <xsl:param name="sentence"/>
  <xsl:result
     select="if (contains($sentence, ‘ ‘))
             then concat(str:reverse(substring-after($sentence, ‘ ‘)),
                         ‘ ‘,
                         substring-before($sentence, ‘ ‘))
             else $sentence"/>
</xsl:function>
<xsl:template match="/">
<output>
  <xsl:value-of select="str:reverse(‘DOG BITES MAN‘)"/>
</output>
</xsl:template>
</xsl:transform>

其他有用的东西

XSLT2.0还有其他有用的新特性,我们在这里难以祥述。包括一种机制,可定义XPath表达式的缺省名称空间(namespace),可在模式匹配判定(match pattern predicates)中使用变量,为排序说明命名(named sort specifications),以非解析文本(unparsed text)的方式读入外部文件等等。

此外,XSLT2.0说明书的一大部分仍在制订中,特别是有关构建和复制W3C XML Schema类型的内容。关于这点,最新的工作草案中说,“这项工作正在进行,有关构建元素和属性的类型信息关联,将可能会出现在XSLT2草案的未来版本中。(This is work in progress. Facilities for associating type information with constructed elements and attributes are likely to appear in future drafts of XSLT 2)”。

时间: 2024-11-06 03:54:55

XSLT 2.0 和 XPath 2.0 的新特性的相关文章

[转]Swift 2.0初探:值得注意的新特性

转自http://www.cocoachina.com/swift/20150623/12231.html 转眼间,Swift已经一岁多了,这门新鲜.语法时尚.类型安全.执行速度更快的语言已经渐渐的深入广大开发者的心.我同样也是非常喜爱这门新的编程语言. 今年6月,一年一度的WWDC大会如期而至,在大会上Apple发布了Swift 2.0,引入了很多新的特性,以帮助开发者能更快,更简单的构建应用.我在这里也说道说道Swift 2.0中值得大家注意的新特性. guard语句 guard语句和if语

Swift 2.0初探:值得注意的新特性

转眼间,Swift已经一岁多了,这门新鲜.语法时尚.类型安全.执行速度更快的语言已经渐渐的深入广大开发者的心.我同样也是非常喜爱这门新的编程语言. 今年6月,一年一度的WWDC大会如期而至,在大会上Apple发布了Swift 2.0,引入了很多新的特性,以帮助开发者能更快,更简单的构建应用.我在这里也说道说道Swift 2.0中值得大家注意的新特性. guard语句 guard语句和if语句有点类似,都是根据其关键字之后的表达式的布尔值决定下一步执行什么.但与if语句不同的是,guard语句只会

FineUI(专业版)v2.6.0即将支持的两个新特性!

特性1:以一挡三,将 160 行代码缩减为 60 行的技巧! 为了更新单元格的编辑值,我们需要下面三个函数同时上阵: GetModifiedDict:修改的单元格值 GetDeletedList:删除的行 GetNewAddedList:新增行 下个版本将用一个函数搞定:GetMergedData ! 老版示例:http://fineui.com/demo_pro/#/demo_pro/grid/grid_editor_cell_new_delete.aspx 新版示例:http://fineu

Spring MVC 3.0.5+Spring 3.0.5+MyBatis3.0.4全注解实例详解(四)

这一章大象将详细分析web层代码,以及使用Spring MVC的注解及其用法和其它相关知识来实现控制器功能.     之前在使用Struts2实现MVC的注解时,是借助struts2-convention这个插件,如今我们使用Spring自带的spring-webmvc组件来实现同样的功能,而且比之以前更简单.另外,还省掉了整合两个框架带来的不稳定因素.     对于Spring MVC框架,我主要讲一下它的常用注解,再结合一些示例进行说明,方便大家能够快速理解.     一.Spring MV

iOS开发——新特性OC篇&amp;Swift 2.0新特性

Swift 2.0新特性 转眼间,Swift已经一岁多了,这门新鲜.语法时尚.类型安全.执行速度更快的语言已经渐渐的深入广大开发者的心.我同样也是非常喜爱这门新的编程语言. 今年6月,一年一度的WWDC大会如期而至,在大会上Apple发布了Swift 2.0,引入了很多新的特性,以帮助开发者能更快,更简单的构建应用.我在这里也说道说道Swift 2.0中值得大家注意的新特性. guard语句 guard语句和if语句有点类似,都是根据其关键字之后的表达式的布尔值决定下一步执行什么.但与if语句不

【redis】redis5.0的一些新特性

redis5.0总共增加了12项新特性,如下: 1.新增加的Stream(流)数据类型,这样redis就有了6大数据类型,另外五种是String(字符串),Hash(哈希),List(列表),Set(集合)及Zset(sorted set有序集合). 2.新的Redis模块api : Times  and Cluster api,是一个抽象的集群消息总线,用于方便开发分布式系统. 3.RDB(redis datebase)现在用于存储 LFU(最近最少使用淘汰算法) 和 LRU(最近不经常使用淘

day07 MyEclipse 安装 jdk5.0 新特性

1.myeclipse的安装和使用 * eclipse:是一个免费的开发工具    * myeclipse:是一个收费的插件,破解myeclipse,        ** 安装目录的要求: 不能有中文和空格        ** 安装完成之后,选择一个工作空间 ,这个工作空间不能有中文和空格    * 破解myeclipse        ** 运行run.bat文件,但是运行之前,必须要安装jdk,通过配置环境变量 * myeclipse的使用        * 创建一个工程          

Atitit.mysql&#160;5.0&#160;5.5&#160;&#160;5.6&#160;5.7&#160;&#160;新特性&#160;新功能

Atitit.mysql 5.0 5.5  5.6 5.7  新特性 新功能 1. MySQL  5.6    5 大新特性1 1.1. 优化器的改进1 1.2. InnoDB 改进1 1.3. 使用 memcached API 直接访问 NoSQL2 1.4. 更好的复制2 1.5. Performance Schema2 2. MySQL 5.7.62 2.1. 内建中文全文索引2 2.2. 多主复制2 2.3. other2 3. 参考2 1. MySQL  5.6    5 大新特性 M

Extjs5.0从入门到实战开发信息管理系统(Extjs基础、Extjs5新特性、Spring、Spring mvc、Mybatis)视频教程

Extjs5.0从入门到实战开发信息管理系统(Extjs基础.Extjs5新特性.Spring.Spring mvc.Mybatis)视频教程下载   联系QQ:1026270010 Extjs作为一款优秀的JS前端开发框架以其良好的架构.丰富的UI组件库.完善的文档和社区支持等诸多优点拥有广泛的市场应用空间,开发人员无需过多的关注HTML.CSS甚至各种常用JS算法,只需把精力放在业务逻辑上,利用各种组件的相互组合调用便可轻松而高效的开发出系统的前端页面. Extjs5在之前版本的基础上又推出