zoukankan      html  css  js  c++  java
  • [转]SharePoint内容定制之XSLT高级用法——使用Muenchian方法分组XML数据

    分组在XSLT处理中是一个很常见的问题,怎样才能将一系列XML节点元素组织到不同的分组里?最常见的情况是处理从数据库中得到的XML输出,数据库通常是根据数据表中的记录生成结果。例如,一个地址簿可能输出下面的内容:

    <records>

    <contact id="0001">

    <title>Mr</title>

    <forename>John</forename>

    <surname>Smith</surname>

    </contact>

    <contact id="0002">

    <title>Dr</title>

    <forename>Amy</forename>

    <surname>Jones</surname>

    </contact>

    ...

    </records>

    现在的问题是怎样把这段文本转换成多个按照surname来分组的列表,例如:

    Jones,<br />

    Amy (Dr)
    <br />

    Brian (Mr)
    <br />

    Smith,
    <br />

    Fiona (Ms)
    <br />

    John (Mr)
    <br />

    通过以下两个步骤可实现这个需求:

    1. 找出都有哪些surname。
    2. 获取具有相同surname值的所有contact节点。

    要找出都有哪些surname就要先找出每个surname对应的第一个contact节点,一个方法就是找出那些surname与先前节点的surname都不同的的contact节点。

    contact[not(surname = preceding-sibling::contact/surname)]

    一旦这些contact节点被找出,就很容易找出它们对应的surname了,然后在此基础上再找出具有相同surname的所有contact节点。

    <xsl:apply-templates select="/records/contact[surname = current()/surname]"/>

    但是对于那些比较大的XML数据(比如海量数据库),这种方法也存在缺点,它使用了两个XPath查询进行了大量的处理。使用preceding-siblings遍历所有前驱兄弟节点会花费大量的时间,尤其是当前节点处于尾部的时候。同样地,查找所有具有某个指定surname的contact节点也会遍历所有contact节点。这种做法效率是很低的。

    Muenchian是由Steve Muench开发的一种分组方法,它通过keys更高效的实现这种需求。Keys通过分配一个key值给一个节点,然后就可以简单的通过key值来访问节点。如果存在多个节点有相同的key值,那么通过这个key值就可以取到所有这些节点。这意味着,如果你想根据节点的某个属性对一组节点进行高效分组时,可以使用keys。

    再回到上面的例子,我们想通过surname来对所有的contact节点分组,于是就创建一个key,并且给每个contact节点一个key值(也就是surname值)。需要分组的节点匹配match属性指定的表达式,key值通过use属性的表达式指定,如下:

    <xsl:key name="contacts-by-surname" match="contact" use="surname"/>

    在key定义好以后,如果知道了surname,我们便可快速查找到相应的contact节点,例如下面的表达式将给出所有surname为Smith的contact节点。

    key('contacts-by-surname', 'Smith')

    然后这就可以很容易实现上面提到的第二个步骤。

    <xsl:apply-templates select="key('contacts-by-surname', surname)"/>

    不过,我们首先需要做的是找出都有哪些surname,同时找出具有某个surname的第一个contact节点。在这里我们可以再次使用keys。当我们把surname作为key的时候,contact节点就已经是这个集合的一部分了,但它是否是集合中的第一个元素呢(按照XML文档顺序)?还是在排在后面?我们仅仅关心集合中的第一个元素。

    要找出一个contact节点是否为由key筛选出的结果中的第一个元素,就要把contact和由key筛选出的结果中的第一个元素作比较。有很多常用的方法可以用来判断两个节点是不是同一个节点:

    1. 比较通过generate-id()函数生成的唯一标识符。

    contact[generate-id() = generate-id(key('contacts-by-surname', surname)[1])]

    2. 检查由这两个节点组成的新集合内部有一个还是两个节点——因为同一个节点在节点集合中不可能出现两次,所以如果这个集合中只有一个元素,那么这之前提到的两个节点肯定就是同一个节点。

    contact[count(. | key('contacts-by-surname', surname)[1]) = 1]

    在找出所有的组以后,可以按照需求对它们排序。同样,组内的节点也可以进行排序。最终,利用下面的这个template,我们就可以分组输出从数据中取到的XML信息。

    <xsl:key name="contacts-by-surname" match="contact" use="surname"/>

    <xsl:template match="records">

    <xsl:for-each select="contact[count(. | key('contacts-by-surname', surname)[1]) = 1]">

    <xsl:sort select="surname"/>

    <xsl:value-of select="surname"/>,<br />

    <xsl:for-each select="key('contacts-by-surname', surname)">

    <xsl:sort select="forename"/>

    <xsl:value-of select="forename"/> (<xsl:value-of select="title"/>)<br />

    </xsl:for-each>

    </xsl:for-each>

    </xsl:template>

    通常,Muenchian是最好的节点分组方法,因为它不需要遍历大量的节点,所以更高效。这种方法特别适用于处理从数据库中获取到的表结构数据,例如以某种层级关系重新组织这些从数据库中得到的数据。它也适用于任何情况下利用XPath可访问到的节点属性对节点集合进行分组。

    Muenchian有一个缺点,它只能在支持keys的XSLT处理器下使用。这就排除了James Clark的xt还有2000年5月以前发布的MSXML。另外,使用keys也是相当消耗内存资源的,因为所有的节点和key值都必须保存在内存中。最后,在多个XML文档之间使用keys进行分组也是一项比较复杂的工作。

    相关链接:

    XSLT Recommendation: Keys

    XSLT Recommendation: generate-id()

    [原文地址:http://www.jenitennison.com/xslt/grouping/muenchian.html]

  • 相关阅读:
    zoj 2316 Matrix Multiplication 解题报告
    BestCoder7 1001 Little Pony and Permutation(hdu 4985) 解题报告
    codeforces 463C. Gargari and Bishops 解题报告
    codeforces 463B Caisa and Pylons 解题报告
    codeforces 463A Caisa and Sugar 解题报告
    CSS3新的字体尺寸单位rem
    CSS中文字体对照表
    引用外部CSS的link和import方式的分析与比较
    CSS样式表引用方式
    10个CSS简写/优化技巧
  • 原文地址:https://www.cnblogs.com/kxlf/p/2230966.html
Copyright © 2011-2022 走看看