新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   >>中国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分组法 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 14330 个阅读者浏览上一篇主题  刷新本主题   平板显示贴子 浏览下一篇主题
     * 贴子主题: [原创翻译]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
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 XSL/XSLT/XSL-FO/CSS 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/4/27 15:45:50

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

     *树形目录 (最近20个回帖) 顶端 
    主题:  [原创翻译]XSLT MUENCHIAN分组法(4400字) - 宇义,2008年12月19日
        回复:  两次转换什么概念?可以举个例子吗?XSLT2.0内置了分组功能,for-each-group。..(77字) - 宇义,2008年12月21日
        回复:  不错,宇义老兄又出现了,每次都有惊喜说点个人意见,还是那句老话,XSL被设计用来处理结构,而不是..(220字) - hexun831012,2008年12月19日
        回复:  不错,谢谢。(16字) - Qr,2008年12月19日

    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    62.500ms