EXSLT 实例

EXSLT 实例 英文原文
内容:
制作日历
简易的数据库操作
结束语
参考资料
关于作者
相关内容:
Investigating XSLT: The XML transformation language
用 EXSLT 扩展 XSLT 的功能
Multi-pass XSLT
在 XML 和 Web 服务专区还有:
教学
工具与产品
所有的文章
如何应用社区标准 XSLT 扩展

Uche Ogbujiuche.ogbuji@fourthought.com
首席顾问,Fourthought, Inc.
2003 年 2 月

从 SAX 到 RDDL,社区标准已经在 XML 技术中起到了非常重要的作用。最重要的 XSLT 社区标准是用于标准扩展函数和元素的 EXSLT 倡议。在本文中,Uche Ogbuji 使用实例来介绍和演示某些有用的 EXSLT 函数。

在最近的 developerWorks 专栏文章“用 EXSLT 扩展 XSLT 的功能”中,Kevin Williams 概括性地介绍了 XSLT 扩展的社区标准。正如他指出,EXSLT 扩展使 XSLT 在通用数据操作任务中变得更加有用。随便选择几个示例:

  • EXSLT Math 模块包含了三角数学函数,这使我们可以用 SVG 生成饼图。
  • EXSLT Regular Expressions 模块使得解析和处理用户输入及其它变量数据源变得更容易。
  • EXSLT Dates and Times 模块使得用对日期敏感的内容来呈现 Web 页面或处理包含日期字段的数据变得更容易。

在这些及其它许多实际任务中,EXSLT 使得可以用一种方式来使用 XSLT,这种方式在支持该标准的许多处理器之间是可移植的。在以前的文章中,我已经说明了 EXSLT 函数(比如 exsl:node-setexsl:object-type)对于哪怕最基本的处理任务而言都非常有用。在本文中我打算通过使用 EXSLT 来解决几个简单而实际的问题,从而有代表性地讨论 EXSLT 功能。而且我不打算介绍我已经介绍过的基础知识,以便介绍许多尚未得到应有重视的 EXSLT 工具。

如果您完全不熟悉 EXSLT,请先阅读 Kevin Williams 的文章。那篇文章的参考资料中包含了到支持 EXSLT 的 XSLT 处理器的链接,您应当安装这些处理器,这样您就可以试验示例并可以亲自使用 EXSLT。通过使用可从 EXSLT 站点下载的 XSLT 脚本,某些 EXSLT 扩展可以由专用的处理器使用。但是用这种方式并未支持所有的 EXSLT 模块,而且这种方式通常会损失许多性能。您可能还希望阅读我在 IBM developerWorks 上对于 EXSLT 的其它讨论。您可以在参考资料中找到此类材料的相关链接。

制作日历

问题:您应客户请求使用 XSLT 在服务器上生成网站。在该网站上,您希望显示当前的日期和时间,以及在某活动发生之前以天数表示的倒计时。

EXSLT Dates and Times 模块提供了许多用于操作日期的函数,包括一个获取当前日期的函数、一些在日期之间执行计算的函数以及其它用于格式化、显示和解释日期的函数。它还提供了 <date:date-format/> 扩展元素,用于对定制日期进行解析和格式化。

清单 1 通过显示当前日期和时间以及到下个月开始所剩的天数来演示这些工具。

清单 1. 用于计算特定于日期的详细信息的样本代码(listing1.xslt)
<?xml version="1.0" encoding="utf-8"?>
<!-- A -->
<xsl:transform
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:date="http://exslt.org/dates-and-times"
    version="1.0"
>
<xsl:output method="html"/>

<!-- B -->
<xsl:variable name="now" select="date:date-time()"/>

<xsl:template match="/">
  <!-- The rest of the Web site HTML material would go here -->
  <xsl:call-template name="date-section"/>
</xsl:template>

<xsl:template name="date-section">
  <p>This page was loaded at <xsl:text/>
    <!-- C -->
    <xsl:value-of select="concat(date:hour-in-day($now), ':',
                                 date:minute-in-hour($now), ':',
                                 date:second-in-minute($now))"/>
    <xsl:text> on </xsl:text>
    <xsl:value-of select="concat(date:day-in-month($now), ' ',
                                 date:month-name($now), ' ',
                                 date:year($now))"/>
  </p>
  <p>
    <!-- D -->
    <xsl:variable name="days-elapsed"
                  select="concat('-P',date:day-in-month($now),'D')"/>
    <xsl:variable name="one-month-hence"
                  select="date:add($now, 'P1M')"/>
    <xsl:variable name="next-month-start"
                  select="date:add($one-month-hence, $days-elapsed)"/>
    <xsl:variable name="seconds"
                  select="date:seconds(
                            date:difference($now, $next-month-start)
                         )"/>
    <xsl:text>The next month starts in </xsl:text>
    <xsl:value-of select="$seconds div (3600*24)"/>
    <xsl:text> days</xsl:text>
  </p>

</xsl:template>

</xsl:transform>

我将依次讨论列表中用字母编号的每一节。

A:首先我声明了 EXSLT dates/times 模块的名称空间:http://exslt.org/dates-and-times。请仔细地正确设置这一名称空间。我见过有些人错误地使用了模块的规范页面 http://www.exslt.org/date/index.html,而没有使用正确的名称空间,这会导致错误。

B:函数 date:date-time 以 ISO-8601 格式将当前日期和时间作为字符串返回,如 2003-01-20T03:16:36Z

C:这里我通过使用允许从日期/时间字符串中抽取各个组成部分的 EXSLT 函数,构造了一个易读的日期和时间表示法。我本来可以用几种方式做到这一点,包括使用 date:date-format 元素,有了该元素,您可以使用格式字符串指定要渲染日期的外观。

D:这里我使用一些计算操作来确定到下个月开始所剩的天数。我本可以用许多方式来执行该计算,其中有些方式比较简单,但是我选取了一组表现为精选品的 EXSLT 函数序列。首先,我计算当月已过去的天数,将它作为 EXSLT 持续时间字符串。EXSLT 持续时间表示正在持续的一段时间而非一个时间段。例如,-P19D 意味着“过去的 19 天”。出于算术目的,持续时间带有符号。例如,如果将时期 P1D12H 加上表示 2003 年 1 月 15 日午夜的日期/时间,那么得到的日期/时间是 2003 年 1 月 15 日中午。如果您加上时期 -P1D12H,则得到的日期/时间是 1 月 14 日中午。这样的计算可以使用 date:add 函数来执行,它接受日期/时间点和持续时间。

接下来我在清单中使用 date:add 计算从现在开始一个月后的日期/时间点。在 $now2003-01-20T03:16:36Z 的情况下,结果是 2003-02-20T03:16:36Z。然后我从刚计算出的日期倒数已过去的天数,得到下个月的第一天 - 例如,2003-02-01T03:16:36Z。函数 date:difference 接受这两个日期/时间点,返回它们之间的持续时间。我用这个函数来计算到下个月开始所剩的持续时间以及这段持续时间内的秒数,如 1036800。最后,我用(3600*24)进行整除,来确定到下个月开始所剩的天数。

该脚本的输出如下所示:


<p xmlns:date="http://exslt.org/dates-and-times">This page was loaded 
at 21:16:36 on 19 January 2003</p>
<p xmlns:date="http://exslt.org/dates-and-times">The next month starts 
in 12 days</p>

注:上面的输出出现在一行上,但为了显示目的已经将它分成几行。

简易的数据库操作

问题:您在 XML 文件中管理着一组记录,并且希望人们能使用通用查询来检索该数据的特定部分。换句话说,您希望在处理其它 XML 数据的同时,能将 XML 文件当作简易的数据库来访问。

考虑清单 2 中的数据文件,它代表了某一组织中的部门和雇员。

清单 2. 雇员的数据文件(employees.xml)
<?xml version="1.0" encoding="utf-8"?>
<employees>
  <department title="Research">
    <employee title="Coordinator">
      <name>
        <given>Rene</given>
        <family>Descartes</family>
      </name>
    </employee>
    <employee title="Project Manager">
      <name>
        <given>Abu</given>
        <family>Al Kwarizmi</family>
      </name>
    </employee>
  </department>
  <department title="Executive">
    <employee title="Chief Executive Officer">
      <name>
        <given>Genghis</given>
        <family>Khan</family>
      </name>
    </employee>
  </department>
  <department title="Wellness">
    <employee title="Manager of Transcendence">
      <name>
        <given>Shakyamuni</given>
        <family>Buddha</family>
      </name>
    </employee>
  </department>
</employees>

现在,假设我们希望人们能编写备忘录,并根据对数据文件的查询,将备忘录发给查询到的人。清单 3 是此类备忘录的一个示例。

清单 3. 根据雇员数据文件查询注明了地址的备忘录(memo.xml)
<?xml version='1.0' encoding='utf-8'?>
<memo>
<title>With Usura Hath no Man a House of Good Stone</title>
<date>2003-01-14</date>
<to>
  <employee-query
    query="/employees/department[@title='Executive']/employee"/>
</to>
<body>
It appears the art world requires a reminder of the fact that the best 
art is created for the enjoyment of the first buyer, and not as as a 
mere investment.  As I've said before, none of the work of Duccio, Piero 
Della Francesca, Pietro Lombardo, Fra Angelico, Zuan Bellini or such 
others would have been of any value if guided by usurious motives.

--EP
</body>
</memo>

to 元素包含了 employee-query 元素,它将被针对雇员数据文件的查询结果所替代。清单 4 是个小型的 XSLT 文件,它通过显示备忘录收件人的真实姓名来演示该过程将如何工作。

清单 4. 显示备忘录收件人的 XSLT 文件(listing4.xslt)
<?xml version="1.0" encoding="utf-8"?>
<!-- A -->
<xsl:transform
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:dyn="http://exslt.org/dynamic"
    version="1.0"
>

<xsl:output method="text"/>

<xsl:template match="/">
  <!-- Jump right to the to element -->
  <xsl:apply-templates select="/memo/to"/>
</xsl:template>

<xsl:template match="to">
  <xsl:apply-templates/>
</xsl:template>

<!-- B -->
<xsl:template match="employee-query">
  <xsl:variable name="db" select="document('employees.xml')"/>
  <xsl:variable name="query" select="@query"/>
  <xsl:for-each select="$db">
    <xsl:variable name="recipients" select="dyn:evaluate($query)"/>
    <xsl:apply-templates select="$recipients"/>
  </xsl:for-each>
</xsl:template>

<xsl:template match="employee">
  <xsl:value-of select="name/given"/>
  <xsl:text> </xsl:text>
  <xsl:value-of select="name/family"/>
  <xsl:if test="not(position()=last())">
    <xsl:text>, </xsl:text>
  </xsl:if>
</xsl:template>

</xsl:transform>

A:请注意我用来设置 EXSLT 模块的另一个名称空间:http://exslt.org/dynamic。该模块包含了几个实时地将字符串作为 XPath 进行处理的函数,并且,在某些情况下,这些函数根据这些字符串进行聚合计算。

B:实际的操作发生在该模板中。首先我将数据文件作为辅助输入读入。然后我将查询字符串存储在一个变量中。我必须这么做,因为我必须马上改变上下文,这样该字符串显示时的属性就不再是可用的了。xsl:for-each 元素实际将上下文变换成数据文件。然后 dyn:evaluate 函数针对该上下文对查询字符串进行动态求值。结果节点集似乎是从正则 XPath 表达式求值中返回的。XSLT 1.0 无法将字符串作为 XPath 表达式进行动态求值,但是我通过使用 EXSLT 获得了该功能。在清单的其余部分,使用常见的 XSLT 操作打印从查询结果的元素获得的姓名。

结束语

EXSLT 包含了可简化工作的工具和首先使事情成为可能的其它工具。例如,在 XSLT 中 date:date-time 函数不可能被替代,但是 dyn:evaluate() 常常可以被系统所替代,然而您可以使用 XSLT 来生成另一个 XSLT 脚本,您实际运行这个脚本以获得预期结果。EXSLT 包含了非常多的内容,我在将来的文章中都无法对此进行逐一讨论,但 EXSLT 的优点在于它有非常好的文档。您可以通过查看网站并利用本文介绍的社区标准找到改进 XSLT 开发所需的丰富工具。

参考资料

  • 如果您不熟悉 XSLT,请阅读由 LindaMay Patterson 所著的“Investigating XSLT: The XML transformation language”,它很好地介绍了 XSLT(developerWorks,2001 年 8 月)。

  • EXSLT 主页是有关该项目的权威信息源。该站点上详细介绍了每一个模块、元素和函数。此外,如果您乐意,可以查找有关将您自己的补充无偿提供给 EXSLT 的信息。为了参与 EXSLT 的讨论,请加入 EXSLT 邮件列表

  • 由 Kevin Williams 所著的“用 EXSLT 扩展 XSLT 的功能”概述了 EXSLT(developerWorks,2002 年 12 月)。由 Leigh Dodds 所著的“Extensions to XSLT”介绍了 EXSLT。

  • 我还在 developerWorks XML 专区的其它文章中讨论了 EXSLT。在“Multi-pass XSLT”中我介绍了 exsl:node-set(2002 年 9 月)。在“Debug XSLT on the fly”的“Introspector Gadget”一节中我介绍了 exsl:object-typedyn:evaluate(2002 年 11 月)。

  • W3C 的 XSL 页面提供了许多有用的 XSLT 相关参考资料的链接,包括规范本身、教程、文章和实现。

  • 请务必将“XSL Frequently Asked Questions”添加到收藏夹中,它着重说明了许多便于调试的要点。

  • 这些示例中所使用的样式表处理器是 4XSLT(属于 4Suite),它是由本文作者共同开发的。

  • 请在 developerWorks XML 专区查找更多的 XML 参考资料。

  • IBM WebSphere Studio 提供了一套使 XML 开发自动化的工具(使用 Java 和其它语言)。它与 WebSphere Application Server 紧紧地集成在一起,但是也可以和其它 J2EE 服务器一起使用。

    关于作者
    Uche Ogbuji 的照片 Uche Ogbuji 是 Fourthought Inc. 的顾问和共同创始人,该公司是专为企业知识管理提供 XML 解决方案的软件供应商和咨询公司。Fourthought 开发了 4Suite,它是一个用于 XML、RDF 和知识管理应用程序的开放源码平台。Ogbuji 先生是一位出生于尼日利亚的计算机工程师和作家,他现在美国科罗拉多州博耳德(Boulder)生活和工作。可以通过 uche.ogbuji@fourthought.com 与 Ogbuji 先生联系。

posted on 2005-01-17 17:47  笨笨  阅读(1475)  评论(1编辑  收藏  举报

导航