您的位置:首页 > 产品设计 > UI/UE

[转贴收藏]XSLT MUENCHIAN分组法

2009-01-16 13:55 176 查看
原文来自http://www.yeeyan.com/articles/view/goto100/20155

简介

在XSLT1.0中如何高效的对扁平结构的XML进行分组。

在XSLT中分组是一个常见问题:如何将一组元素排列成组?一种最常见的情况就是将数据库中的数据通过XML进行输出。通常数据库返回的XML结构是与数据库中的记录一样的。例如一个地址簿,它可能会给你如下XML:

Mr John Smith Dr Amy Jones ...问题是如何将这个平坦的输入变成一个通过surname分组的列表,输出成如下格式:

Jones,
Amy (Dr)
Brian (Mr)
Smith,
Fiona (Ms)
John (Mr)
这个解决方案分两步:

不重复的找出所有surname;
取得所有的等于当前surname的contact。
要不重复的找出contact中出现的所有surname,可以找surname的第一次出现。方法是找到那些在前面所有的contact中的surname是没有出现过的contact:

contact[not(surname = preceding-sibling::contact/surname)]当这些contact已经被确定,找到等于它的surname就很容易了,方法是找到所有的等于当前surname的contact:

这种方法的最大问题在一个很大的XML文件中这两个XPath将使用过多的处理时间(比如它们来自于一个大数据库)。在XML中通过“preceding-siblings”搜索所有的前置兄弟节点轴越后面的元素会越慢。类似的,每次找所有等于一个确定的surname的contact将会遍历所有的contact节点,这使得它非常效率低下。

Muenchian方法是Steve Muench通过使用更快速的key方法提高分组功能的效率而开发的一种方法。key给一个节点分配一个key值,您便可以通过key值方便的获得那个节点。如果有很多节点使用同一个key值,那么当你使用key值时那些所有的节点也都会被检索到。这意味着如果你想要将一组节点通过它们的某一个属性进行分组,你可以使用key将它们进行分组。

我们还是用上面的地址簿例子。我们希望通过将contact通过它们的surname分组,于是我们建立一个key,分配给所有的contact一个来自于它的surname的key值。我们希望分组的节点应该在“match”属性中进行匹配。我们想要使用的key值通过“use”属性指定:

通过定义这个key,如果我们知道一个surname,就可以快速的获得所有的等于那个surname的contact。比如:

key('contacts-by-surname', 'Smith')将返回所有surname为“Smith”的contact。所以它很容易的满足了上面所提到的第二个步骤(取得所有相同surname的contact):

我们需要解决的第一个步骤是确定这个XML中包含了哪些surname,这涉及到确定第一个contact出现在XML中的surname。这里我们可以再次使用key。我们已经知道当我们将surname作为key的时候contact是一组节点的一部分:问题是它是那组节点中的第一次出现(按照文档中的节点排序)还是第n次出现?我们仅仅需要数据中的第一次出现。

比较当前contact是否是等于当前contact的surname的所有contact中的第一个。有两种通用的方法可以测试两个节点是否相同:

比较两个节点唯一的生成标实(使用generate-id()):
contact[generate-id() = generate-id(key('contacts-by-surname', surname)[1])]看节点集中是一个节点还是两个节点组成的——节点集不能包含相同的节点,所有节点集中如果只有一个节点,那么它们一定是相同的:
contact[count(. | key('contacts-by-surname', surname)[1]) = 1]当你已经确定了分组,你可以用任意的顺序排列它们。类似的,你可以在分组中任意的排列节点。下面是一个模板,它建立了我们指定的从数据库中取得的XML的输出:

,
()
Muenchian方法是通常情况下用来从XML源节点分组并输出的最好的方法,因为它并没有遍历很多的节点,因此它的效率更高。尤其是它特别适合当你有一个从数据库中取得的平坦的XML输出的情况,比如你需要结构成等级。它适用于很多情况比如当你需要通过使用XPath检索某个元素的属性将节点机进行分组时。

不足的是Muenchian方法只能工作在支持key的XSLT处理器中。在James Clark的xt和2000年6月之前的MSXML版本中不能使用。并且使用key将会占用相当多的内存,因为所有的节点集和它们的key值将会存储在内存中。最后,当需要分组的节点来自不同的文档时,使用key会相当麻烦。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: