除非你整个假期一直在看《萤火虫》(Firefly)全集和电影《冲出宁静号》(即Serenity,根据Firefly改编),并比较家庭成员向洗劫一个小镇的Reavers怪物打开他们的礼物,否则你可能已经听说现在万维网联盟在推荐XSLT 2.0。
你想到的问题是——现在推荐XSLT 2.0是什么意思?简单来说,这表示XSLT 2.0就像刻在了石头上,那些编写XSLT的程序员现在可以使用它,写他们的XSLT处理器,而不必担心被最后一刻的改变弄得不知所措。
不过,对我来说,XSLT 2.0得到正式采用和度假这两件事激发我建立一个XSLT 2.0最佳功能的简短列表。你可以把它看作是一个“最佳”特性集,我认为它们是最常用的一些特性。XSLT 1.0中有一些特性,我发现我一年之中也只用了一两次。除开那些现在无益的特性,我主要讨论那些能够立即满足应用程序开发需求的特性。
分组
我发现,似乎每次我开始写一个XSL式样表,随后就需要用到分组信息。这种需求可能是由于某种对数据进行分类,使其更具可读性的深层次要求所引起的;或者只是由于我神经过敏!可能制定这些要求的人以前在国家狩猎委员会工作:“你可以钓一只鲑鱼和六磅其它供垂钓的鱼或一磅供垂钓的鱼和一只鲑鱼。”如果你曾经看过有关钓鱼方面的法律,你就会明白我的意思。
在XSLT 1.0中,使用分组就像在冒险,这些事情需要不断实践,像是在洞穴探险时不被Grue怪吃掉。XSLT 1.0中的首选分组方法叫做Meunchian分组,它由Oracle的Steve Meunch开发。
它的工作方式如下:编码一个xsl:key元素,指定将会用作关键字的元素或属性,以及关键字提交的元素。比较每个关键字的第一个实例提交的元素的ID和文档中的相同元素ID即可完成分组。如果两个ID匹配,则节点相同。这保证式样表中每个关键字只处理一次,并可以处理含有那个关键字值的所有元素。
下面列出一个XML样本文档和一个XSLT 1.0 Muenchian分组实例,如列表A和B。
列表A——XML样本文档
<?xml version="1.0" encoding="UTF-8"?>
<world>
<country name="Canada" continent="North America">
<city>Toronto</city>
<city>Vancouver</city>
</country>
<country name="Jamaica" continent="North America">
<city>Kingston</city>
<city>Ocho Rios</city>
</country>
<country name="United States" continent="North America">
<city>Allentown</city>
<city>Mobile</city>
</country>
<country name="United Kingdom" continent="Europe">
<city>London</city>
<city>Dundee</city>
</country>
<country name="France" continent="Europe">
<city>Paris</city>
<city>Nice</city>
</country>
<country name="Japan" continent="Asia">
<city>Tokyo</city>
<city>Osaka</city>
</country>
</world>
列表B——XSLT 1.0 Muenchian分组
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="" xmlns:fo="">
<xsl:key name="keyContinent" match="//country" use="@continent"/>
<xsl:template match="/">
<xsl:element name="world">
<xsl:for-each select="//country[generate-id(.) = generate-id(key('keyContinent',@continent)[1])]">
<xsl:sort select="@continent" data-type="text" order="ascending"/>
<xsl:variable name="continent" select="@continent"/>
<xsl:apply-templates select="//country[@continent = $continent]" mode="group">
<xsl:sort select="@name" data-type="text" order="ascending"/>
</xsl:apply-templates>
</xsl:for-each>
</xsl:element>
</xsl:template>
<xsl:template match="*" mode="group">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
在XSLT 2.0中,分组方法有了一些改变,但应该指出的是,Meunchian分组方法依然可用。所不同的是,Meunchian分组为可选方法,因为XSLT 2.0中内置了分组功能,因此实际上不必再使用Meunchian分组。开发者可以使用xsl:for-each-group来代替它,如列表C所示。
列表C——XSLT 2.0中的分组
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="" xmlns:fo="" xmlns:xs="" xmlns:fn="" xmlns:xdt="">
<xsl:template match="/">
<xsl:element name="world">
<xsl:for-each-group select="//country" group-by="@continent">
<xsl:sort select="@continent" data-type="text" order="ascending"/>
<xsl:variable name="continent" select="@continent"/>
<xsl:apply-templates select="//country[@continent = $continent]" mode="group">
<xsl:sort select="@name" data-type="text" order="ascending"/>
</xsl:apply-templates>
</xsl:for-each-group>
</xsl:element>
</xsl:template>
<xsl:template match="*" mode="group">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
虽然这些分组方法各不相同,但它们的最终结果是一样的,如列表D所示。