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

    >> 在这里讨论其他W3C规范
    [返回] 中文XML论坛 - 专业的XML技术讨论区W3CHINA.ORG讨论区 - Web新技术讨论『 其他W3C规范 』 → 技巧:将 XSLT 查找表打包成 EXSLT 函数 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 14827 个阅读者浏览上一篇主题  刷新本主题   平板显示贴子 浏览下一篇主题
     * 贴子主题: 技巧:将 XSLT 查找表打包成 EXSLT 函数 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     oceans 帅哥哟,离线,有人找我吗?
      
      
      等级:大一新生
      文章:10
      积分:173
      门派:XML.ORG.CN
      注册:2005/2/28

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给oceans发送一个短消息 把oceans加入好友 查看oceans的个人资料 搜索oceans在『 其他W3C规范 』的所有贴子 引用回复这个贴子 回复这个贴子 查看oceans的博客楼主
    发贴心情 技巧:将 XSLT 查找表打包成 EXSLT 函数

    使用社区标准 XSLT 扩展
    级别: 中级

    Uche Ogbuji (uche.ogbuji@fourthought.com)
    首席顾问, Fourthought, Inc.
    2005 年 2 月

    在前一篇技巧文章中,Uche Ogbuji 示范了如何用 XSLT 建立查找表。在后续技巧文章中,他又介绍了如何处理这种查找中的错误和默认条件。这篇技巧将说明如何使用 EXSLT(XSLT 扩展的社区标准)的函数模块,以及如何通过将代码打包成易于重用的函数来改进这项技术。
    在“XSLT lookup tables”和“技巧:XSLT 查找表中的默认值和错误处理”这两篇技巧中,我说明了如何创建 XSLT 代码来查找为处理程序提供的静态值,其中包括默认值和错误处理的支持。处理这类查找的代码非常简单但是相当笨拙,尤其是在转换中使用多个表的时候。清单 1 是查找表的示例实现(摘自最近的那篇技巧),在查找失败时,它可以提供默认值。

    清单 1. 带有默认值的查找表示例(states-lookup-default.xslt)
    <?xml version="1.0"?>
    <xsl:transform
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:s="http://example.com/states.data"
      version="1.0"
    >

      <xsl:output method="text"/>

      <xsl:key name="state-lookup" match="s:state" use="s:abbr"/>

      <xsl:variable name="states-top" select="document('')/*/s:states"/>

      <xsl:template match="label">
        <xsl:value-of select="name"/>
        <xsl:text> of </xsl:text>
        <xsl:apply-templates select="$states-top">
          <xsl:with-param name="curr-label" select="."/>
        </xsl:apply-templates>
      </xsl:template>

      <xsl:template match="s:states">
        <!-- This template updated to add a default value signal -->
        <xsl:param name="curr-label"/>
        <xsl:variable name="look-for" select="$curr-label/address/state"/>
        <xsl:variable name="default" select="s:default"/>
        <xsl:variable name="result"
          select="key('state-lookup', $look-for)/s:name"/>
        <xsl:choose>
          <xsl:when test="$result">
            <xsl:value-of select="$result"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="$default"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:template>

      <s:states>
        <s:state><s:abbr>CO</s:abbr><s:name>Colorado</s:name></s:state>
        <s:state><s:abbr>CT</s:abbr><s:name>Connecticut</s:name></s:state>
        <s:state><s:abbr>ID</s:abbr><s:name>Idaho</s:name></s:state>
        <s:state><s:abbr>NJ</s:abbr><s:name>New Jersey</s:name></s:state>
        <!-- Added default value -->
        <s:default><s:name>[UNKNOWN]</s:name></s:default>
      </s:states>

    </xsl:transform>
      

    在 XSLT 1.0 中进行模块化的局限性
    您可能希望将键查找代码打包在指定模板中,使代码更加清晰。清单 2 就是这样做的,这种方法不是很好,但在没有其他复杂因素(或者没有查找类型的限制)的情况下,这已经是 XSLT 1.0 所能做到的最好的表现了。

    清单 2. 将查找代码打包成可重用的模板
    <?xml version="1.0"?>
    <xsl:transform
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:s="http://example.com/states.data"
      version="1.0"
    >

      <xsl:output method="text"/>

      <xsl:key name="state-lookup" match="s:state" use="s:abbr"/>

      <xsl:variable name="states-top" select="document('')/*/s:states"/>

      <xsl:template match="label">
        <xsl:value-of select="name"/>
        <xsl:text> of </xsl:text>
        <xsl:call-template name="lookup">
          <xsl:with-param name="key-name" select="'state-lookup'"/>
          <xsl:with-param name="look-for" select="address/state"/>
          <xsl:with-param name="default" select="$states-top/s:default"/>
          <xsl:with-param name="table-doc" select="$states-top"/>
        </xsl:call-template>
      </xsl:template>

      <xsl:template name="lookup">
        <xsl:param name="key-name"/>  <!-- name of XSLT key -->
        <xsl:param name="look-for"/>  <!-- what to look up -->
        <xsl:param name="default"/>
        <!-- Node set whose first item can be used to set the proper context
             for key lookup. -->
        <xsl:param name="table-doc"/>
        <!-- Force context to document where the lookup table is defined -->
        <xsl:for-each select='$table-doc[1]'>
          <xsl:variable name="result" select="key($key-name, $look-for)"/>
          <xsl:choose>
            <xsl:when test="$result">
              <xsl:value-of select="$result"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$default"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:for-each>
      </xsl:template>

      <s:states>
        <s:state><s:abbr>CO</s:abbr><s:name>Colorado</s:name></s:state>
        <s:state><s:abbr>CT</s:abbr><s:name>Connecticut</s:name></s:state>
        <s:state><s:abbr>ID</s:abbr><s:name>Idaho</s:name></s:state>
        <s:state><s:abbr>NJ</s:abbr><s:name>New Jersey</s:name></s:state>
        <!-- Added default value -->
        <s:default><s:name>[UNKNOWN]</s:name></s:default>
      </s:states>

    </xsl:transform>
      

    清单 2 的主要问题是,查找总是通过 $result 的字符串值在 lookup 模板中呈现。但这不是我所期望的。如果标签是“CO”,我希望显示“Colorado”。在清单 2 中,$result 的值是“COColorado”,因为查找的结果是整个匹配的 s:state 元素。与清单 1 相比,在清单 1 中,通过选择 s:name 子元素,就可以立即将查找结果限制为目标字符串。

    不同的查找情况需要不同的 XPath 表达式,从 XSLT key 返回的节点中提取特定的结果。为了解决上述问题,您可能希望以某种方式在 lookup 模板中传递用于 XSLT key 结果的 XPath 表达式。但是这样做需要能够动态指定 XPath,而 XSLT 1.0 没有提供这种能力。或者,您也许认为可以将 xsl:call-template 放在一个 xsl:variable 中,然后从该变量获得需要的 s:name 子元素。但这样做也不行,因为创建的变量将计算得到一个结果树片段(RTF),而 XSLT 1.0 不允许对 RTF 执行轴操作(axis operation)。

    清单 2 还提出了其他一些不那么显著的问题。整个 xsl:call-template 结构笨拙而冗长。XSLT key 的行为有一个容易造成混乱的要求,即使用 xsl:for-each 将上下文变成查找表文档中的一个节点,这个文档通常仍然与源文档(该例中是样式表文档本身)有所不同。

    让 EXSLT 来帮忙
    除了最后一个问题之外,使用 EXSLT 可以很好地解决其他所有问题。清单 3 中的代码完全模仿了清单 1 的行为,并使用两个 EXSLT 函数解决了上述的问题。它还允许进行整洁的打包。

    清单 3. 清单 1 的正确模块化,使用 EXSLT
    <?xml version="1.0"?>
    <xsl:transform version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:s="http://example.com/states.data"
      xmlns:func="http://exslt.org/functions"
      xmlns:dyn="http://exslt.org/dynamic"
      extension-element-prefixes="func"
    >

      <xsl:output method="text"/>

      <xsl:key name="state-lookup" match="s:state" use="s:abbr"/>

      <xsl:variable name="states-top" select="document('')/*/s:states"/>

      <xsl:template match="label">
        <xsl:value-of select="name"/>
        <xsl:text> of </xsl:text>
        <xsl:value-of
          select="s:lookup('state-lookup', address/state,
                           $states-top/s:default, $states-top,
                           '$result/s:name')"/>
      </xsl:template>

      <func:function name="s:lookup">
        <xsl:param name="key-name"/>  <!-- name of XSLT key -->
        <xsl:param name="look-for"/>  <!-- what to look up -->
        <xsl:param name="default"/>
        <!-- Node set whose first item can be used to set the proper context
             for key lookup. -->
        <xsl:param name="table-doc" select="$default"/>
        <!-- A string containing an XPath expression to be evaluated to
             get the final result.  By default, just render the XSLT key
             result as is -->
        <xsl:param name="result-expr" select="'$result'"/>
        <!-- Force context to document where the lookup table is defined -->
        <xsl:for-each select='$table-doc[1]'>
          <xsl:variable name="result" select="key($key-name, $look-for)"/>
          <xsl:choose>
            <xsl:when test="$result">
              <func:result select="dyn:evaluate($result-expr)"/>
            </xsl:when>
            <xsl:otherwise>
              <func:result select="$default"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:for-each>
      </func:function>

      <s:states>
        <s:state><s:abbr>CO</s:abbr><s:name>Colorado</s:name></s:state>
        <s:state><s:abbr>CT</s:abbr><s:name>Connecticut</s:name></s:state>
        <s:state><s:abbr>ID</s:abbr><s:name>Idaho</s:name></s:state>
        <s:state><s:abbr>NJ</s:abbr><s:name>New Jersey</s:name></s:state>
        <!-- Added default value -->
        <s:default><s:name>[UNKNOWN]</s:name></s:default>
      </s:states>

    </xsl:transform>
      

    与期望的相同,用户定义函数 s:lookup 可以在多数查找中重用。可以从第一个模板中看到更简洁 XPath 语法是如何简化查找代码。函数调用中传递的参数顺序与函数定义中 xsl:param 的顺序对应。func:result 扩展用于确定回传给调用者的值。在其他方面,用户定义函数体的行为类似于 XSLT 1.0 模板。这种技术提供了很大的灵活性。下面的片段是调用函数的另一种方法,它也能很好地工作:


        <xsl:value-of
          select="s:lookup('state-lookup', address/state,
                           $states-top/s:default, $states-top')/s:name"/>
      

    用户定义函数可以巧妙地绕开 XSLT 的 RTF 限制。

    结束语
    您可以找到很多克服 XSLT 1.0 缺点和局限性的 EXSLT 扩展。这篇技巧介绍了如何使用 EXSLT 简化已经非常棒的 XSLT 1.0 技术。


       收藏   分享  
    顶(1)
      




    ----------------------------------------------
    [url=http://www.id-consulting.com.cn]管理咨询[/url] [url=http://www.jinlingdry.com]干燥设备[/url] [url=http://www.tiaoma.com.cn]条码扫描器[/url] [url=http://www.sanxia.org.cn]三峡之窗[/url] [url=http://www.cpmi.org.cn]项目管理[/url]

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

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

     *树形目录 (最近20个回帖) 顶端 
    主题:  技巧:将 XSLT 查找表打包成 EXSLT 函数(8801字) - oceans,2005年3月3日

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