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]

  • 相关阅读:
    MySQL操作表中的数据
    mysql查询语句进阶
    mysql基本查询语句
    mysql函数
    mysql约束
    操作MySQL表
    操作MySQL数据库
    mysql视图
    as2 播放停止音效
    as3 深复制
  • 原文地址:https://www.cnblogs.com/kxlf/p/2230966.html
Copyright © 2011-2022 走看看