以文本方式查看主题 - 中文XML论坛 - 专业的XML技术讨论区 (http://bbs.xml.org.cn/index.asp) -- 『 DTD/XML Schema 』 (http://bbs.xml.org.cn/list.asp?boardid=23) ---- XML 问题 #5:使用 XSLT 转换 DocBook 文档 (http://bbs.xml.org.cn/dispbbs.asp?boardid=23&rootid=&id=11929) |
-- 作者:anchen0617 -- 发布时间:11/9/2004 3:31:00 PM -- XML 问题 #5:使用 XSLT 转换 DocBook 文档 通过使用 DocBook 示例,David Mertz 演示了如何通过 XSLT (可扩展样式表语言转换)将 XML 文档转换成 HTML。这位无畏的专栏作家一共讨论了四种转换 XML 文档的可选方式,并和我们分享了他试验某些开放源码工具的经历。样本代码包括了 XSLT 文档片段、以 XSLT 表示的简单 DocBook 章节的有效 HTML 输出器代码,以及一个简要的 XSLT 循环示例。
欢迎来到 XML 转换的世界!我想您可能不会一帆风顺:标准正在接合并进行修订、工具还不成熟并经常有错误、实现不一致,并且选择非常混乱。但不要惊慌。我可以为您指引至少一条走出迷宫的途径。而且随着时间的推移,情况必定会有所改善,尽管改善的速度往往不如我们所愿。 首要事情 在本专栏中,我们假设您已经有了一些结构良好、格式正确、有效的 DocBook XML 文档。首先非常好的事是拥有它们,但下一步是将它们转换成更加方便的最终用户格式:例如 HTML 页面、PDF 文件和印刷页面(读者实际所阅读的)等。这正是我在将部分归档作品转换成 DocBook 后所面临的问题,本文提供了我自己的解决方案。 我的主要目标 -- 至少目前 -- 是到 HTML 的正确转换。但我不希望限于 HTML 输出。还有一些更小的目标。我希望对精确输出具有某些控制而无需执行许多操作,也无需了解许多新的语言和技术。我还希望使用免费的工具和跨平台的工具。最后,我希望将依赖性降低到最小。即使所有必需的贡献都是免费和跨平台的,大量复杂的依赖性也是个缺点。基本上,我的理想是有一个独立的可执行程序,只运行,可靠地运行,将我的 DocBook 文档以我所希望的样式转换成 HTML。高不可攀的梦想,但为什么不能这么想呢? 执行转换的方式 编写定制转换代码。最好从一种具有基本 XML 方法库的编程语言(例如 SAX 和 DOM)开始。但即使假设基本语法分析是个黑箱,定制代码也可以对语法分析过的元素执行所有您希望执行的操作。归根结底,这是最灵活和最强大的方式,但也往往会带来更多工作,不论是事先的还是维护的。 XSLT.com 列出的许多其它 XSLT 工具也是自由软件。不过,它们中的大多数是 Java 程序,也要依赖于各种额外的 Java 库。用户似乎给了一些 Java 工具正面评价,因此这些工具对您来说可能是很好的选择。我选择 Sablotron 是因为编译过的 C 速度更快,安装和使用都很简单。 Norman Walsh 为 DocBook 创建了一系列完整的 XSLT 样式表。不幸的是,将它们用在样式表时,Sablotron 崩溃了,并且 XML Spy 不能匹配有效 DocBook 文档中的任何东西。这很可能是工具而不是 Walsh 样式表的一个限制。使用其它工具可能运气会好些。这个问题仍然给了我们开发定制(不很完整)XSLT 样式表的机会,无论如何这是我真正希望的(为了演示技术)。 Sablotron 的使用非常简单。基本用法是: 清单 1: Sablotron 的基本用法 X:\mydocs> x:\sabl\bin\sabcmd mystyle.xsl mydoc.xml
它说的是:使用 mystyle.xsl 中的规则来将 mydoc.xml 转换成 mydoc.html,如果希望,也可以使用管道和重定向。设置 Sablotron 和解开它的档案一样容易(它还提供了能从程序调用的库,但最好从命令行实用程序中使用。)因此可以按环境需要调整路径和文件名。 编写 XSLT 规范 “ 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"
可以看到,chapter.xsl 是个格式正确的 XML 文件。您还将注意到,模式 <xsl:*> 是 XSLT 文档中许多标记的名称。实际上,所有属于指令的标记都象这样。在转换到类似 XML 格式(例如 HTML)的过程中,将看到各种其它标记。这些其它标记属于目标格式,只在 <xsl:*> 元素中出现。 基本上,应该确切使用如上指出的名称空间属性(xmlns:xsl 和 xmlns)。可能还希望保留输出行;尽管可以使用 xml 或 text 方法。 上面的 XSLT 文件作为处理模板使用得非常好。但这可能不是您所需要的。可以假设因为缺少输出规范而没有任何输出。这不完全正确:它仍然捕捉所有文本节点,并提供简单 ASCII 版本的章节(使用上述样式表)。如果确实希望没有一点输出,需要有类似清单 3 中的一个 XSLT 文档: <xsl:stylesheet version="1.0" <xsl:template match="*"> </xsl:stylesheet>
null 输出器使我们的转换更有用。真正的样式表实际上只描述了一系列要尝试匹配的模式,模板在每个提供输出内容模板的 <xsl:template> 元素内部。如示例所示,"*" 可以与任何模式匹配。我们的示例碰巧没有在模板中做任何事,但它仍然努力与源 XML/DocBook 文档中可能出现的任何元素匹配。 通过下降进行匹配 清单 4: 最小章节 XSLT 文档 (minimal.xls) <xsl:stylesheet version="1.0" <xsl:template match="chapter"> </xsl:template> <xsl:template match="*"> </xsl:stylesheet>
使用该样式表和 DocBook 章节运行 XSLT 处理器时,得到的结果类似于: 清单 5: 使用样式表和 DocBook 章节的 XSLT 处理器 ----- Start of Chapter -----
该输出不那么有用,但它让我们看到样式表做了些什么。章节的根元素是 <chapter> 标记。样式表匹配 <chapter> 标记,并打印 " - - - - - Start of Chapter - - - - - "。各种子代出现在 <chapter> 元素中。每一这样的子代都称为非章节内容,因此将匹配 "*" 模板。 为开发自己的 XSLT 样式表,提供类似上面非匹配元素的某些明显标记,可以让您很快看到需要开发哪些模板。清单 6 显示了带有一些真实模板的版本: 清单 6: 有效的 HTML 输出器 XSLT 文档 <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"> <xsl:template match="chapter/title"> <xsl:template match="para"> <xsl:template match="*"> </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 只能出现在还不匹配的标记内部)。为进行准确的衡量,模板仍然匹配 "*",因此可以在检查输出时看到样式表不完整。 重复的子代 清单 7: 在子元素上循环的 XSLT 模板 <xsl:template match="simplelist">
不用下降到 simplelist 中的每个子元素,我们只假设子元素都是 <member> 元素。 <xsl:for-each> 的工作方式与嵌套模板非常相似,而且与编程语言循环构造也非常相似。 <xsl:for-each> 元素的内容将出现在匹配 select 属性的每个子元素的输出中。在循环中,当前 <member> 元素的内容成为下降到我们在循环中找到的 <xsl:apply-templates/> 标记的活动节点。就是说,列表中的每样事物在其内部都有进一步的标记,我们将这些元素的格式传递给它们相应的模板(对于文本节点,它们就是文字格式的输出)。 未来 |
W 3 C h i n a ( since 2003 ) 旗 下 站 点 苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》 |
10,660.160ms |