首 页 | 新 闻 | 技术中心 | 第二书店 | 《程序员》 | 《开发高手》 | 社 区 | 黄 页 | 人 才
移 动专 题SUNIBM微 软微 创精 华Donews人 邮
我的技术中心 
我的分类 我的文档
全部文章 发表文章
专栏管理 使用说明



 RSS 订阅 
最新文档列表
Windows/.NET
.NET  (rss)    
Visual C++  (rss)    
Delphi  (rss)    
Visual Basic  (rss)    
ASP  (rss)    
JavaScript  (rss)    
Java/Linux
Java  (rss)    
Perl  (rss)    
综合
其他开发语言  (rss)    
文件格式  (rss)    
企业开发
游戏开发  (rss)    
网站制作技术  (rss)    
数据库
数据库开发  (rss)    
软件工程
其他  (rss)    

积极原创作者 
coofucoo (109)
Aoouch (11)
NinGoo (28)
amh (72)
nizhigang2000 (8)
superyan (27)
iiprogram (83)
hongbo781202 (81)
Kendiv (113)
TechnoFantasy (52)
CSDN - 文档中心 - 网站制作技术 阅读:2895   评论: 1    参与评论
标题   XSLT问答:分组、计数和上下文     选择自 onestab 的 Blog
关键字   XML, XSLT
出处   http://www.xml.com/pub/a/2002/07/31/qa.html

XSLT问答:分组、计数和上下文

原作:John E. Simpson 2002.07.31
翻译: onestab 2002.08.03

问: 怎样计算具有某个属性值的元素的个数(How do I count the number of elements with a given attribute value)?

我的XML文件是这样的:

   <Match>
      <Date>21/3/2005</Date>
      <Stadium>Wembley</Stadium>
      <Team Name="Liverpool">
         <Goal Scorer="O'Reilly"/>
         <Goal Scorer="Smith"/>
         <Goal Scorer="O'Reilly"/>
      </Team> 
      <Team Name="Real Madrid">
         <Goal Scorer="Charles"/>
         <Goal Scorer="Humble"/>
         <Goal Scorer="Humble"/>
         <Goal Scorer="Santana"/>
         <Goal Scorer="Humble"/>
      </Team>
   </Match>

我想得到这样的输出(对利物浦队):

   Player   Goals
   O'Reilly 2
   Smith    1

怎么办?

答:问的好。解答这个问题要掌握一些XSLT技术:分组(使用XSLT key)和使用count()函数。

这就是解决这个问题的XSLT样式表片断;注意下面代码中的粗体字部分:

   <xsl:key name="player" match="@Scorer"use="."/>
   <xsl:template match="Team">
      <table border="1">
         <tr><th colspan="3">Team: <xsl:value-of select="@Name"/></th></tr>
        
         <tr><th>Player</th><th>Goals</th><th>Gen'd ID</th></tr>
         <xsl:for-each select="Goal/@Scorer[generate-id()=generate-id(key('player',.))]">
            <tr>
               <td><xsl:value-of select="."/></td>
               <td><xsl:value-of select="count(../../Goal[@Scorer=current()])"/></td>
               <td><xsl:value-of select="generate-id(.)"/></td>
            </tr>
         </xsl:for-each>
      </table>
      <br />
   </xsl:template>

该代码片断首先设置了一个XSLT key --有点像数据库术语中的索引。这个key的名字为"player";它与@Scorer的XPath表达式给出的模式相匹配。有了use属性,这个key的值就是与模式相匹配的字符串。注意xsl:key元素是个顶级元素,它是根元素xsl:stylesheet的子元素。除非这个key被某些低级的样式表模板或指令中的key()函数实际调用,在整个原始树中,这个匹配模式不“相对(relative)”于任何东西(这一点不像是可以相对的上下文节点)。更重要的是,与数据库中的索引或XML的ID属性的唯一性不同,XSLT的key可以一次指向一个以上的“东西”。与ID类型的属性的另一处不同,这些key被严格地限定于元素的识别。在这种情况下,我们要做的就是根据取值相同的的属性来分组:即文件中的 Scorer元素。

这个样式表片断有一条模板规则。对于由xsl:templatematch属性所找出的每个Team元素,这个模板构造出一个有三列的表格。两列用来显示每个队中得分队员的名字和进球数,我增加的第三列仅仅用来演示key的工作原理。

在模板规则中我们首先感兴趣的是里面的xsl:for-each元素,它的 select属性显然可以开始 -- “对于Team元素上下文中的每个Goal子元素的Scorer属性”-- 当它接着往下进行推断时,就似乎无所适从了。

这种推断的原理是所谓的Muenchian方法,它用一种非文件结构“内建的(built-in)”的方式对数据进行分组。这种技术的名字源于Oracle公司的Steve Muench,是他首先在XSLT -List邮件列表中提出这种方法。它利用了XSLT的generate-id()函数的几个特性:

  • 在为原始树中的某个节点产生唯一的标识符时,XSLT处理器不被要求按照某种特定的算法。
  • 然而,不管采用什么算法,当一个实例正被处理的时候,对于任何给定的“种子”值(比如节点的字符串值),XSLT必须产生同样的键值。(对于每次(every)处理实例来说,不要求根据给定的种子值所产生的键值相同。)

这个推断的实际含义是,将select属性所找出的节点集限定于那些其Scorer属性满足下列条件的节点: 由其产生的ID与根据当前Scorer属性所产生的值完全相同。(to restrict the node-set located by the select attribute to just those Scorer attributes whose generated IDs are identical to that of the current Scorer attribute)。分组过程如下:对于每个唯一Scorer属性值,在表中增加一行,而不是对每个Scorer属性都增加一行(或者说两行是O'Reilly的,三行是Humble的)。

模板规则中以粗体显示的另一部分是对每个唯一的Scorer属性值计算进球数。count()函数有一个参数 --在这里是一个以相对路径表示的XPath表达式。这个路径告诉count()函数计算出当前节点的“爷爷”的所有Goal子元素数量,只要这些Goal元素的Scorer属性值与当前的Scorer属性值相同,

还请注意current()函数的用法。在大多数情况下,当前的节点就是上下文节点(context node)。在xsl:for-each块中有些特别,这两者未必相同。在xsl:value-of元素的select属性中调用current()函数时,上下文节点已经转移到由先前的count()函数的参数部分所选择的那个Goal元素,当然这个元素的字符值肯定不等于Scorer属性的值,所以,(a) 这个推断永远不成立,(b) 没有相匹配的节点可以选择,(c) 进球数当然总是零。或者说,当前节点不受xsl:value-of所重设的上下文节点所影响;在这个例子中,当前节点总是由xsl:for-each循环的当前一轮所建立的节点,也就是说,当前的(keyed)Scorer属性值。

表中的第三列演示了generate-id()函数对于每个唯一Scorer元素是如何工作的。另外,要记住前面所列出的两个规则:对于任何指定的“种子”值,得出的结果是唯一的,XSLT处理器可以用任何算法,只要它能保证在一次处理当中对相同的种子值能得出相同的结果。这里是Microsoft的MSXML解析器在某次处理中所得出的表格形式:

XSLT keys generated by MSXML processor

如果你采用Saxon来处理XSLT代码,得到的转换结果可能是这样的:

XSLT keys generated by Saxon 6.2processor

注意,在第三列中,两种处理器用来产生ID时采用的算法相当不同,但在重要的两列仍然产生了相同的结果:计算出了进球数,按得分者分组。如果去掉第三列,这两个处理器(以及别的兼容的处理器)产生的结果完全一致。


相关文章
对该文的评论
hdw1978 ( 2003-01-13)
如果在"Real Madrid" 有一个同样叫做 的进球就不能显示出来