David Mertz,博士
转换专家, Gnosis Software, Inc.
2000 年 11 月
内容: |
|
|
首要事情 |
方法 |
选择 XSLT 工具 |
编写 XSLT 规范 |
通过世系进行匹配 |
重复的子代 |
未来 |
参考资料 |
关于作者 |
|
通过使用
DocBook
示例,David Mertz 演示了如何通过 XSLT (可扩展样式表语言转换)将 XML 文档转换成 HTML。这位无畏的专栏作家一共讨论了四种转换 XML 文档的可选方式,并和我们分享了他试验某些开放源码工具的经历。样本代码包括了 XSLT 文档片段、以 XSLT 表示的简单
DocBook
章节的有效 HTML 输出器代码,以及一个简要的 XSLT 循环示例。
欢迎来到 XML 转换的世界!我想您可能不会一帆风顺:标准正在接合并进行修订、工具还不成熟并经常有错误、实现不一致,并且选择非常混乱。但不要惊慌。我可以为您指引至少一条走出迷宫的途径。而且随着时间的推移,情况必定会有所改善,尽管改善的速度往往不如我们所愿。
首要事情
最后两个“XML 问题”专栏描述了我将学术文章转换成 XML 的项目,具体来说是转换到
DocBook
DTD 的项目。那些文章提供了一个编写您自己的
DocBook
文档的良好起点,这就是本专栏目的所在。
在本专栏中,我们假设您已经有了一些结构良好、格式正确、有效的
DocBook
XML 文档。首先非常好的事是拥有它们,但下一步是将它们转换成更加方便的最终用户格式:例如 HTML 页面、PDF 文件和印刷页面(读者实际所阅读的)等。这正是我在将部分归档作品转换成
DocBook
后所面临的问题,本文提供了我自己的解决方案。
我的主要目标 — 至少目前 — 是到 HTML 的正确转换。但我不希望限于 HTML 输出。还有一些更小的目标。我希望对精确输出具有某些控制而无需执行许多操作,也无需了解许多新的语言和技术。我还希望使用免费的工具和跨平台的工具。最后,我希望将依赖性降低到最小。即使所有必需的贡献都是免费和跨平台的,大量复杂的依赖性也是个缺点。基本上,我的理想是有一个独立的可执行程序,只运行,可靠地运行,将我的
DocBook
文档以我所希望的样式转换成 HTML。高不可攀的梦想,但为什么不能这么想呢?
执行转换的方式
至少有四种可能的方式来将
DocBook
文档 — 或几乎所有 XML 文档 — 转换成最终用户格式。我很认真地为我的小项目考虑过所有四种方式。本专栏只详细讨论最后一种选项,但在您规划涉及到重复转换的项目时,有必要记住所有方式:
-
编写定制转换代码。
最好从一种具有基本 XML 方法库的编程语言(例如 SAX 和 DOM)开始。但即使假设基本语法分析是个黑箱,定制代码也可以对语法分析过的元素执行所有您希望执行的操作。归根结底,这是最灵活和最强大的方式,但也往往会带来更多工作,不论是事先的还是维护的。 -
使用级联样式表和
DocBook
文档。
这是一种想法。最好能将排版规范完全与结构化标记分离,并只让客户机设备(例如浏览器)产生良好的输出。这有可能发生,但就目前来说,似乎支持有限 — 只在 IE 5.5、Opera 4 和某些最新的 Mozilla 开发者发行版中支持。现在这不象是可以依靠最终用户为他们执行这些任务的方法。 -
使用文档样式语义和规范语言 (DSSSL) 来指定到目标格式的转换。
从好的方面说,已经存在一些
DocBook
(以及其它格式)DSSSL 样式表。DSSSL 基本上是一门需要学习的全新编程语言,而且是类似于 Lisp 的功能性语言。为利用 DSSSL,需要从 Jade 或 OpenJade 开始,但这两种工具都很复杂,以至于许多人都必须为它们编写封装器(例如 SGML-tools Lite)。为了获得有用的系统 — 虽然有报告说是个非常好的有效系统 — 您确实需要满足所有种类的系统依赖性,并安装所有种类的工具和库。对于某些有良好意愿,然而可能没有投入足够精力的尝试,我没能让与 Jade 相关的工具在我的系统上顺利地发挥作用。很明显,有其他许多人每天都在使用这些系统,所以稍微多做一些工作一定能把事情办得井井有条。(如果您能指点一个快速、简单、多合一的 DSSSL 处理器,请告诉我。我非常希望尝试一下。)然而除了安装困难外,DSSSL 感觉上象是来自与 XML 技术不同的传统和思考方法,相反,最后一个方法基本上是纯 XML,并来自正式(有效)的 W3C 规范。 -
使用可扩展样式表语言转换 (XSLT)。
从某种意义上说,XSLT 实际上是 XML 文档类的一个规范。即,XSLT 样式表本身是格式正确的 XML 文档,并带有一些专门的内容,可以让您“模板化”您所期望的输出格式(继续阅读它的含义)。有许多工具至少从名义上支持 XSLT:我的预感是,这确实是 XML 转换的技术方向 — 因为,或者尽管,相对于 W3C 的“正式”身份。XSLT 可以指定到任何目标格式的转换。但给我的一般感觉是,大多数开发者发现,在目标格式是另一种 XSLT 格式(例如 XHTML)时,使用 XML 更容易。
选择 XSLT 工具
参考资料
部分包含了到许多 XSLT 工具描述的链接。我尝试过其中的许多,但发现 Sablotron 最合我口味。它是自由软件 (GNU)。它是多平台的。它有许多独立的可执行程序,这些程序可以简单地从命令行运行。最重要的是,它看起来能正确工作,至少对于我的简单测试案例来说如此。
XSLT.com 列出的许多其它 XSLT 工具也是自由软件。不过,它们中的大多数是 Java 程序,也要依赖于各种额外的 Java 库。用户似乎给了一些 Java 工具正面评价,因此这些工具对您来说可能是很好的选择。我选择 Sablotron 是因为编译过的 C 速度更快,安装和使用都很简单。
Norman Walsh 为
DocBook
创建了一系列
完整的
XSLT 样式表。不幸的是,将它们用在样式表时,Sablotron 崩溃了,并且 XML Spy 不能匹配有效
DocBook
文档中的任何东西。这很可能是工具而不是 Walsh 样式表的一个限制。使用其它工具可能运气会好些。这个问题仍然给了我们开发定制(不很完整)XSLT 样式表的机会,无论如何这是我真正希望的(为了演示技术)。
清单 1: Sablotron 的基本用法
X:/mydocs> x:/sabl/bin/sabcmd mystyle.xsl mydoc.xml mydoc.html |
它说的是:使用
mystyle.xsl
中的规则来将
mydoc.xml
转换成
mydoc.html
,如果希望,也可以使用管道和重定向。设置 Sablotron 和解开它的档案一样容易(它还提供了能从程序调用的库,但最好从命令行实用程序中使用。)因此可以按环境需要调整路径和文件名。
编写 XSLT 规范
有关 XSLT 的实质,请阅读 W3C 的官方建议书(请参阅
参考资料
部分)。本文旨在提供让它工作的更多非正式细节。
“
XML 问题 #3
”和“
XML 问题 #4
”中介绍的特定
DocBook
文档 (
chap5.xml
) 是一
章
。示例使用了章节中所有可能的
DocBook
标记中相当小的一部分。所以目前来说,我们实际上所需要的就是
chapter.xsl
文件,它将对
chap5.xml
中实际使用的每个标记做些有用的事。这是适当的开始,但易于构建是因为 XSLT 具有开放和可扩展的本质。让我们看一下。
从
chapter.xsl
的骨架开始 — “如何将
DocBook
章节转换成 HTML”模板:
清单 2: 骨架 XSLT 文档 (empty.xls)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/TR/xhtml1/strict"> <xsl:output method="html" indent="yes" encoding="UTF-8"/> </xsl:stylesheet> |
可以看到,
chapter.xsl
是个格式正确的 XML 文件。您还将注意到,模式
<xsl:*>
是 XSLT 文档中许多标记的名称。实际上,所有属于指令的标记都象这样。在转换到类似 XML 格式(例如 HTML)的过程中,将看到各种其它标记。这些其它标记属于目标格式,只在
<xsl:*>
元素中出现。
基本上,应该确切使用如上指出的名称空间属性(
xmlns:xsl
和
xmlns
)。可能还希望保留输出行;尽管可以使用
xml
或
text
方法。
上面的 XSLT 文件作为处理模板使用得非常好。但这可能不是您所需要的。可以假设因为缺少输出规范而没有任何输出。这不完全正确:它仍然捕捉所有文本节点,并提供简单 ASCII 版本的章节(使用上述样式表)。如果
确实
希望没有一点输出,需要有类似清单 3 中的一个 XSLT 文档:
清单 3: Null 输出 XSLT 文档 (null.xls)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/TR/xhtml1/strict"> <xsl:output method="html" indent="yes" encoding="UTF-8"/> <xsl:template match="*"> </xsl:template> </xsl:stylesheet> |
null 输出器使我们的转换更有用。真正的样式表实际上只描述了一系列要尝试匹配的模式,模板在每个提供输出内容模板的
<xsl:template>
元素内部。如示例所示,”*” 可以与任何模式匹配。我们的示例碰巧没有在模板中
做
任何事,但它仍然努力与源 XML/
DocBook
文档中可能出现的任何元素匹配。
通过下降进行匹配
XSLT 的威力主要在于它们扩展匹配功能的能力。一旦匹配了一个元素,XSLT 就将匹配功能扩展到该元素的子元素。通过在 null 输出器上进行扩展,让我们创建一个有一定意义的样式表。允许下降到子元素的重要标记是
<xsl:apply-templates>
。一般来说,每个模板都在其主体中包括这个标记:
清单 4: 最小章节 XSLT 文档 (minimal.xls)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/TR/xhtml1/strict"> <xsl:output method="html" indent="yes" encoding="UTF-8"/> <xsl:template match="chapter"> ----- Start of Chapter ----- <xsl:apply-templates/> </xsl:template> <xsl:template match="*"> ##### Unmatched Element in Source ##### </xsl:template> </xsl:stylesheet> |
使用该样式表和
DocBook
章节运行 XSLT 处理器时,得到的结果类似于:
清单 5: 使用样式表和
DocBook
章节的 XSLT 处理器
----- Start of Chapter ----- ##### Unmatched Element in Source ##### ##### Unmatched Element in Source ##### ##### Unmatched Element in Source ##### |
该输出不那么有用,但它让我们看到样式表做了些什么。章节的根元素是
<chapter>
标记。样式表匹配
<chapter>
标记,并打印 ” – – – – – Start of Chapter – – – – – “。各种子代出现在
<chapter>
元素中。每一这样的子代都称为非章节内容,因此将匹配 “*” 模板。
为开发自己的 XSLT 样式表,提供类似上面非匹配元素的某些明显标记,可以让您很快看到需要开发哪些模板。清单 6 显示了带有一些真实模板的版本:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/TR/xhtml1/strict"> <xsl:output method="html" indent="yes" encoding="UTF-8"/> <xsl:template match="chapter"> <html> <head> <title> <xsl:value-of select="title"/> </title> </head> <body> <xsl:apply-templates/> </body> </html> </xsl:template> <xsl:template match="chapter/title"> <hr></hr> <h1><xsl:apply-templates/></h1> </xsl:template> <xsl:template match="para"> <p><xsl:apply-templates/></p> </xsl:template> <xsl:template match="*"> ##### Unmatched Element in Source ##### </xsl:template> </xsl:stylesheet> |
该 HTML 输出器显示了 XSLT 样式表的某些实际特性。
chapter
模板匹配对希望产生的 HTML 文档进行排版。模板匹配内部的 HTML 标记没有什么特别;您放在那里的所有文本都将出现在输出中。在 HTML
<title>
元素中,使用
<xsl:value-of>
指令将
<chapter>
内部必需的
title
子元素插入到
DocBook
。在 HTML
<body>
元素中,将控制传递给其它模板(大概
DocBook
中极少的一部分)。
chapter
后的下一个模板是
chapter/title
。这意味着匹配
<title>
元素,但只有在它直接出现在
<chapter>
内部时。如果希望,可以只匹配
title
,从而指定源文档中每个
<title>
元素的输出格式。但我希望将章节标题格式化成不同于
sect1
的标题、
sect2
的标题等。使用示例中的
para
(但从不真正匹配,因为
para
只能出现在还不匹配的标记内部)。为进行准确的衡量,模板仍然匹配 “*”,因此可以在检查输出时看到样式表不完整。
重复的子代
通过下降匹配模板不是 XSLT 唯一的技巧。还可以执行有条件的输出、排序、取出源属性,然后在子代上循环。就目前来说,只需要看一下清单 7 中简单的循环示例:
<xsl:template match="simplelist"> <ul> <xsl:for-each select="member"> <li><xsl:apply-templates/></li> </xsl:for-each> </ul> </xsl:template> |
不用下降到
simplelist
中的每个子元素,我们只假设子元素都是
<member>
元素。
<xsl:for-each>
的工作方式与嵌套模板非常相似,而且与编程语言循环构造也非常相似。
<xsl:for-each>
元素的内容将出现在匹配
select
属性的每个子元素的输出中。在循环中,当前
<member>
元素的内容成为下降到我们在循环中找到的
<xsl:apply-templates/>
标记的活动节点。就是说,列表中的每样事物在其内部都有进一步的标记,我们将这些元素的格式传递给它们相应的模板(对于文本节点,它们就是文字格式的输出)。
未来
前面的资料只揭开了 XSLT 的面纱。但它应该为您提供了使用样式表和转换的一些认识。
参考资料
部分提供了进一步阅读相关问题的许多来源。特别是通过阅读本文档案文件中更完整的 XML 和 XSLT 示例能从中获益。请别走开,本专栏将以各种方式再回来介绍 XSLT。
参考资料
-
转至万维网协会的
XSL 主页
,获得可扩展样式表语言 (XSL) 的完整描述和说明。 -
万维网协会 (W3C) 的
XSLT 建议书 1.0
提供了 XML 名称空间机制的概述。它还是了解 XSL 转换(XSLT)语法和语义的定义的好地方。 -
XSLT.com
提供了对许多 XSLT 工具进行调查的总结。 -
Sablotron XSL 转换处理器
(开放源码)可对公众使用,并且作为多平台 XML 应用程序的基础非常方便。 -
仔细查看 XSLT 工具的
Norman Walsh 的 XSL 样式表
调查。 -
Joe Brockmeier 的 ”
A gentle guide to
DocBook
” 是对 SGML-tools Lite 的详细介绍。这是另一种 — 使用 DSSSL — 用于格式化
DocBook
文档的方式,与 XSLT 方式不同。 -
如果希望了解更多有关 DSSSL 的信息,James Clark 的
文档样式语义和规范语言 (DSSSL)
页面是个好的起点。 -
OASIS 有关 XML 工具的建议书
提供了“用于
DocBook
的已知”资源。 -
IBM alphaWorks 的
Xeena XML Editor
(90 天之内免费许可证),是用于编辑从任何有效 DTD 中派生出的有效 XML 文档的常规 Java 应用程序。 -
请阅读
webreview.com
上 David Mertz 的 XML Spy 评论。 - 如需商业 XML 编辑器,请检查:
-
-
XML Spy 主页
(图标信息系统) -
SoftQuad 的 XMetal 主页
; -
Extensibility 的 XML 实例
。
-
-
要确认 XML 文档,转至 Scholarly Technology Group 的
基于 Web 的 XML 确认格式
(可以获得源码,许可不限)。 -
最好从
DocBook
: The Definitive Guide
, Norman Walsh & Leonard Muellner, O’Reilly, Cambridge, MA 1999 开始理解有关
DocBook
更详细的信息。或者仔细查看它的
电子版本
。 -
结构化信息标准提高组织
(OASIS)
是一家非赢利性的国际联合会,基于例如 XML 和 SGML 这样的公用标准来“创建可以互操作的行业规范 . . . ” -
下载
本文中使用和提到的文件。 -
在
developerWorks
的
Doug Tidwell 的三部分教程
中了解有关 XSLT 转换的更多信息,该教程演示了许多不同文档是如何转换成 HTML、PDF 和 SVG 格式的。 -
尝试 Ken Holman 的
演示预览格式的 Crane Softwrights XSLT 教程。
- 另请参阅 David Mertz 以前的专栏:
关于作者
David Mertz 一定在他的其它一篇文章中错放了他的 MacGuffin。它将很快出现。可以通过
mertz@gnosis.cx
与 David 联系;在
http://gnosis.cx/publish/
上详细介绍了他的生活。非常欢迎对过去的、这一篇或将来的专栏文章提出意见和建议。