内容


技巧

如何用 XSLT 组合文档

探索 XPath 功能

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: 技巧

敬请期待该系列的后续内容。

此内容是该系列的一部分:技巧

敬请期待该系列的后续内容。

XSLT 不仅功能强大而且还具备了很高的灵活性,这着实吸引人。XSLT 不仅对发布网站有用,而且对转换或操作 XML 文档也很有用。既然 XSLT 处理器已随 Java 平台一起提供(通过 javax.xml.transform 包),那么您就不能忽略它。

XSLT 程序员总是面临的一个问题是,应该如何处理多个文档?Java API 只期望有两个参数:源文档(输入 XML 文档)和结果文档(用于保存输出的位置)。虽然该 API 适合于许多应用程序,但在某些情况下,您需要组合几个源文档。有这样一些示例:

  • 邮件合并,譬如在直邮市场营销的活动中,人们用样式表将客户文件中的姓名和地址与信件模板合并起来。
  • 转换代码列表,譬如产品引用。国家或地区代码常需要将目录文件与存储在一个单独文件中的代码列表相匹配。
  • 为了出版而组合几个单独的文档。例如,当出版一本书时,可能希望将各章节文件合并起来,或者 — 正如您将在下一节看到的 — 将照片文件合并起来。

示例

下面这个示例展示了如何使用 XML 和 XSLT 来合并用于出版的多个文档。每幅照片有两个文件:照片本身(JPEG 格式)和带有标题、日期和位置的 XML 描述。描述文件可能类似于清单 1。

清单 1. geneva.xml — 有关照片的 XML 描述
<?xml version="1.0"?>
<ph:photo xmlns:ph="http://ananas.org/2003/tips/photo">
<ph:title>The Jet d'Eau fountain</ph:title>
<ph:location>Geneva</ph:location>
<ph:date>April 2003</ph:date>
<ph:description>
The Jet d'Eau fountain is the most recognizable symbol of Geneva.
The fountain reaches 140 meters (460 feet) high, roughly the same height
as the Embassy Suites hotel in Times Square.
</ph:description>
</ph:photo>

清单 1 中的标记很简单。不用花很长时间就可以编写一个用 HTML 发布该文档的样式表。更令人感兴趣的问题是,如何创建一个图库,使它将清单 1 以及其它照片描述(譬如清单 2 中的描述)组合起来?(在可下载的代码中,您会发现更多的照片描述,可以在 参考资料中找到这些代码。)

清单 2. london.xml — 另一个有关照片的 XML 描述
<?xml version="1.0"?>
<ph:photo xmlns:ph="http://ananas.org/2003/tips/photo">
<ph:title>Double-decker bus</ph:title>
<ph:location>London</ph:location>
<ph:date>October 2002</ph:date>
<ph:description>
An inescapable symbol of London, the double-decker bus is much taller
than typical buses to carry many passengers through the city's overcrowded
streets.
</ph:description>
</ph:photo>

在继续之前,我想向您展示一些定义。通过 Java API 传递给样式表的 XML 文档被称为 主源文档。由样式表装入的其它文档被称为 辅助源文档

document() 函数

由于 Java API 只接受一个源文档,因此必须从样式表自身装入辅助源文档。这是通过 document() 函数实现的,它将 URI 作为参数。该函数解析文档,然后返回节点集。

为完整起见, document() 还接受节点集作为参数,在这种情形下,该函数认为每个节点都是一个 URI。最后,您可以将字符串和节点集的组合作为参数来传递。该函数组合字符串和节点集来确定装入哪些文档。尽管如此,在大多数情况下,传递单个 URI 更简单。

例如,下面这个 XPath 装入 geneva.xml 文档,如 清单 1所示:

document('geneva.xml')

因为 document() 返回一个节点集,您几乎可以将这个节点集插入到 XPath 有效的任何地方。更明确地讲,可以将选择器添加到路径。例如,下面的 XPath 装入 geneva.xml 文档,并返回该文档的标题:

document('geneva.xml')/ph:photo/ph:title

带有 document() 函数的 XPath 可以出现在 XPath 有效的任何地方,譬如 xsl:value-ofxsl:apply-templates 指令的 select 属性。所以,为了显示文档标题,可以编写下面这条指令:

<xsl:value-of select="document('geneva.xml')/ph:photo/ph:title"/>

当为辅助源文档编写 XPath 时,要小心。很容易忘记根元素,如果您确实忘记了,那么 XPath 会返回空的节点集。例如,如果我忘记了 XPath 中的 ph:photo (辅助文档的根元素),那么会得到以下的 XPath ,它返回空的节点集:

document('geneva.xml')/ph:title

组合文档

为了进行汇总,在用 XSLT 组合文档时,希望从主源文档开始,然后装入辅助源文档。最方便的解决方案之一是,在主源文档中列出辅助源文档。主源文档类似于清单 3 所示 — 清单 3 只是列出了要组合的文档(并提供了该集合的标题)。

清单 3. index.xml 列出了辅助源文档
<?xml version="1.0"?>
<ph:index xmlns:ph="http://ananas.org/2003/tips/photo">
<ph:title>City sights</ph:title>
<ph:entry>geneva</ph:entry>
<ph:entry>london</ph:entry>
<ph:entry>paris</ph:entry>
<ph:entry>roma</ph:entry>
</ph:index>

清单 4 是样式表本身。它定义了用于主源文档和辅助源文档中各元素的模板。主源文档和辅助源文档之间的链接在 ph:index 模板中,由该模板解析辅助源文档。 xsl:apply-templates 指令意味着处理器遍历辅助源文档,并在遍历过程中应用这些模板。实际上,它处理时就好象辅助源文档包含在主源文档中一样。

清单 4. merge.xsl 样式表 — 用于处理主源文档中列出的文档
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ph="http://ananas.org/2003/tips/photo">
<xsl:output method="html"/>
<xsl:template match="ph:index">
<html>
<head><title><xsl:value-of select="ph:title"/></title></head>
<xsl:apply-templates/>
</html>
</xsl:template>
<xsl:template match="ph:index/ph:title">
<h1>xsl:apply-templates/></h1>
</xsl:template>
<xsl:template match="ph:entry">
<img src="{concat(.,'.jpg')}" align="right"/>
        <xsl:apply-templates select="document(concat(.,'.xml'))"/>
<br clear="right"/>
</xsl:template>
<xsl:template match="ph:photo/ph:title">
<h2>xsl:apply-templates/></h2>
</xsl:template>
<xsl:template match="ph:location">
<h3>in <xsl:apply-templates/></h3>
</xsl:template>
<xsl:template match="ph:date">
<p>Date: <xsl:apply-templates/></p>
</xsl:template>
<xsl:template match="ph:description">
<p><xsl:apply-templates/></p>
</xsl:template>
</xsl:stylesheet>

将清单 4 应用到 清单 3的结果是生成一个带有所有照片的 HTML 文档。这种方法的好处之一是,通过编辑 index.xml 文档,可以向图库添加照片,也可以从图库除去照片。而且,很容易在不同的图库之间共享照片。假如您还想要一个有更多关于日内瓦(Geneva)照片的图库。只需要创建另一个类似于 清单 3并指向这些照片的列表即可。可以在这两个图库中包含 清单 1中的描述,但不必去复制它。

其它应用

在本篇技巧文章中所描述的这项技术可以应用到很多场合。可以用 document() 函数来创建涉及多个文件的索引或目录。我还曾使用该技术来检索链接标题:只要采用 document() 函数的 URI,就可以恢复文档标题。我还曾用该技术来遍历每天的日志并生成月度报告。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML
ArticleID=22084
ArticleTitle=技巧: 如何用 XSLT 组合文档
publish-date=08012003