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

    >> 本版讨论XSL,XSLT,XSL-FO,CSS等技术
    [返回] 计算机科学论坛XML.ORG.CN讨论区 - XML技术『 XSL/XSLT/XSL-FO/CSS 』 → 技巧:在 XSLT 中用递归实现循环(转) 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 5646 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: 技巧:在 XSLT 中用递归实现循环(转) 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     菜籽 帅哥哟,离线,有人找我吗?双鱼座1981-2-28
      
      
      威望:5
      头衔:软件民工
      等级:研二(Sowa的知识表示写得真好!)
      文章:875
      积分:5655
      门派:XML.ORG.CN
      注册:2004/7/25

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给菜籽发送一个短消息 把菜籽加入好友 查看菜籽的个人资料 搜索菜籽在『 XSL/XSLT/XSL-FO/CSS 』的所有贴子 点击这里发送电邮给菜籽 引用回复这个贴子 回复这个贴子 查看菜籽的博客楼主
    发贴心情 技巧:在 XSLT 中用递归实现循环(转)

    XSLT 是一种函数式编程语言,类似于 Haskell 或 Scheme,但是与 C 和 Fortran 不同。因此这种语言没有循环,也没有可变的变量。相反,必须用递归和参数来代替这些结构。这篇技巧示范了如何使用命名模板和 xsl:call-template、xsl:with-param、xsl:param 元素来提供这种功能。
    XSLT 是图灵完成的(Turing complete)。也就是说,如果有足够的内存,那么 XSLT 可以完成其他任何图灵完成语言(如 C++)所能完成的计算。对于属性更传统的语言的程序员来说,这可能有点奇怪。毕竟 XSLT 缺少对很多算法来说极其重要的特性,其中包括循环和可变的变量。

    注意:XSLT 所谓的变量在其他多数语言中称为常量。它们更像是代数变量而不是传统的编程变量。

    函数式编程
    上述的遗漏并非疏忽所致。XSLT 是一种函数式语言而不是过程性语言。在 C 或 Pascal 这样的过程性语言中,程序被定义成一系列的步骤,这些步骤按照规定的顺序执行,并在最后一步产生最终结果。在函数式语言中,程序被定义成由其他函数组成的函数,函数求值形成最终的结果。函数式语言的最大优点是执行的顺序无关紧要。作为一个简单的例子,考虑下面两个(代数)函数:

    f(x) = 2*x
    g(x) = x - 3

    设函数 h(x) 是 f 与 g 的复合函数:

    h(x) = f(g(x))

    对该函数求值可以先计算 g:

    h(x) = f(x - 3) = 2 * (x - 3) = 2x - 6

    也可以先计算 f:

    h(x) = 2 * g(x) = 2 * (x - 3) = 2x - 6

    两者的结果是一样的。语言的函数式使其更适合并行处理,因为问题的多个部分可以同时计算,无需担心其中的一部分要先于其他部分计算。线程安全是自动实现的。

    函数式语言包括 XSLT,但不能包含传统的循环,因为循环在时间上是有序的。就是说,典型循环的编写和编译必须保证 i==1 出现在 i==2 之前。当然,也可以反向而不是正向运行循环,或者使用 1 之外的循环计数器增量,甚至像 while 语句那样完全取消循环计数器。但是无论什么类型的循环,执行的顺序都至关重要,这一点与函数式编程正好相反。

    递归
    函数式编程中,传统语言中用循环完成的多数任务都可以使用递归来完成。参数代替了变量。比如,最近有人问我如何输出在编译时不知道数量的点(句点)。比方说,格式化菜单时可能要用到,因为在菜名和价格之间常常需要不同数量的点:

    Crawfish Etoufee.......$9.95
    Fried Chicken..........$6.95

    在 C 语言中可以编写一个简单的函数:

    void printDots(int n) {

      int i;

      for (i = 0; i < n; i++) {
        printf(".");
      }
      
    }

    但是这并不是解决问题的惟一办法。可以用递归代替循环,比如:

    void printDotsRecursively(int n) {

      if (n > 0) {
        printf(".");
        printDots(n-1);
      }
      
    }

    在 C 中很少这样做,但是在 XSLT 中,这是惟一的办法。

    下面的模板准确地生成 count 参数所传递的数量的点。逻辑很简单:如果 $count 的值大于零,就输出一个点,将 count 参数减去 1 后再调用这个函数;否则什么也不做。这与 printDotsRecursively 函数采用的算法基本相同,只不过是用 XSLT 而非 C 实现的:

      <xsl:template name="dots">
      
          <xsl:param name="count" select="1"/>

          <xsl:if test="$count > 0">
            <xsl:text>.</xsl:text>
            <xsl:call-template name="dots">
              <xsl:with-param name="count" select="$count - 1"/>
            </xsl:call-template>
          </xsl:if>
          
      </xsl:template>

    比如要输出 100 个点,用 100 count 参数值调用该函数:

        <xsl:call-template name="dots">
          <xsl:with-param name="count" select="100"/>
        </xsl:call-template>

    如果不希望传递一个常数值,那么还可以根据其他数据计算要打印的点数。比如,下面的指令分别计算价格和菜名的长度(更具体地说,是上下文节点中 price 和 entree 子元素的 string-values 函数值)后,输出足够做的点数将每个菜单行填充到 80 个字符:

        <xsl:call-template name="dots">
          <xsl:with-param name="count"
                    select="80 - string-length(entree) - string-length(price)"/>
        </xsl:call-template>

    结束语
    无论是在 C、XSLT 中,还是在 Scheme 中,都应用了使用递归代替循环。但是这种技术非常优雅。在 XSLT 中不需要经常使用这种技术,但使用这种技术可以完成用其他任何标准 XSLT 技术都做不到的技巧性任务。


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    重拾英语...

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2005/8/23 18:52:00
     
     GoogleAdSense双鱼座1981-2-28
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 XSL/XSLT/XSL-FO/CSS 』的所有贴子 点击这里发送电邮给Google AdSense 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2025/6/26 10:03:47

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

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