新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论XSL,XSLT,XSL-FO,CSS等技术
    [返回] 中文XML论坛 - 专业的XML技术讨论区XML.ORG.CN讨论区 - XML技术『 XSL/XSLT/XSL-FO/CSS 』 → [原创翻译]XSLT MUENCHIAN分组法 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 14335 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: [原创翻译]XSLT MUENCHIAN分组法 举报  打印  推荐  IE收藏夹 
       本主题类别: 样式表技术(XSL, XSLT, XSL-FO, CSS) | XML文档存取技术(DOM, SAX)    
     宇义 帅哥哟,离线,有人找我吗?
      
      
      等级:大二(研究汇编)
      文章:22
      积分:297
      门派:XML.ORG.CN
      注册:2005/6/27

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给宇义发送一个短消息 把宇义加入好友 查看宇义的个人资料 搜索宇义在『 XSL/XSLT/XSL-FO/CSS 』的所有贴子 引用回复这个贴子 回复这个贴子 查看宇义的博客楼主
    发贴心情 [原创翻译]XSLT MUENCHIAN分组法

    原文:http://www.jenitennison.com/xslt/grouping/muenchian.xml

    在XSLT中分组是一个常见问题:如何将一组元素排列成组?一种最常见的情况就是将数据库中的数据通过XML进行输出。通常数据库返回的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。

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

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

    当这些contact已经被确定,找到等于它的surname就很容易了,方法是找到所有的等于当前surname的contact:

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

    这种方法的最大问题在一个很大的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”属性指定:

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

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

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

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

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

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

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

       1. 比较两个节点唯一的生成标实(使用generate-id()):

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

       2. 看节点集中是一个节点还是两个节点组成的——节点集不能包含相同的节点,所有节点集中如果只有一个节点,那么它们一定是相同的:

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

    当你已经确定了分组,你可以用任意的顺序排列它们。类似的,你可以在分组中任意的排列节点。下面是一个模板,它建立了我们指定的从数据库中取得的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方法是通常情况下用来从XML源节点分组并输出的最好的方法,因为它并没有遍历很多的节点,因此它的效率更高。尤其是它特别适合当你有一个从数据库中取得的平坦的XML输出的情况,比如你需要结构成等级。它适用于很多情况比如当你需要通过使用XPath检索某个元素的属性将节点机进行分组时。

    不足的是Muenchian方法只能工作在支持key的XSLT处理器中。在James Clark的xt和2000年6月之前的MSXML版本中不能使用。并且使用key将会占用相当多的内存,因为所有的节点集和它们的key值将会存储在内存中。最后,当需要分组的节点来自不同的文档时,使用key会相当麻烦。


       收藏   分享  
    顶(0)
      




    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2008/12/19 11:59:00
     
     Qr 帅哥哟,离线,有人找我吗?
      
      
      威望:9
      等级:博士二年级(版主)
      文章:4392
      积分:29981
      门派:XML.ORG.CN
      注册:2004/5/15

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给Qr发送一个短消息 把Qr加入好友 查看Qr的个人资料 搜索Qr在『 XSL/XSLT/XSL-FO/CSS 』的所有贴子 访问Qr的主页 引用回复这个贴子 回复这个贴子 查看Qr的博客2
    发贴心情 
    不错,谢谢。

    ----------------------------------------------
    没人帮忙,那就靠自己,自己才是最好的老师!本人拒绝回答通过站内短消息提出的问题!

    blog:http://Qr.blogger.org.cn

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2008/12/19 13:07:00
     
     hexun831012 帅哥哟,离线,有人找我吗?天秤座1983-10-12
      
      
      威望:1
      等级:研二(Pi-Calculus看得一头雾水)(版主)
      文章:800
      积分:5114
      门派:XML.ORG.CN
      注册:2006/12/8

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给hexun831012发送一个短消息 把hexun831012加入好友 查看hexun831012的个人资料 搜索hexun831012在『 XSL/XSLT/XSL-FO/CSS 』的所有贴子 引用回复这个贴子 回复这个贴子 查看hexun831012的博客3
    发贴心情 
    不错,宇义老兄又出现了,每次都有惊喜
    说点个人意见,还是那句老话,XSL被设计用来处理结构,而不是结构里的数据,所以分组对XSL来说,并不怎么适合
    个人有的想法,如果实在需要通过XSL进行分组,以我个人的经验,2次转换是最好的方式
    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2008/12/19 21:46:00
     
     宇义 帅哥哟,离线,有人找我吗?
      
      
      等级:大二(研究汇编)
      文章:22
      积分:297
      门派:XML.ORG.CN
      注册:2005/6/27

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给宇义发送一个短消息 把宇义加入好友 查看宇义的个人资料 搜索宇义在『 XSL/XSLT/XSL-FO/CSS 』的所有贴子 引用回复这个贴子 回复这个贴子 查看宇义的博客4
    发贴心情 
    两次转换什么概念?可以举个例子吗?

    XSLT2.0内置了分组功能,for-each-group。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2008/12/21 0:22:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 XSL/XSLT/XSL-FO/CSS 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/5/1 10:10:00

    本主题贴数4,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    82.031ms