用 XML 写作

现在我已经用 XML 完成了大部分写作,甚至包括我的上一本书。当我向人们提到这一点时,他们会问一些关于我经验的问题,这足以促使我写这篇文章来谈谈整个过程。

2003 年 1 月



我的写作之路

第一步 - 重构目录

我从 2000 年左右开始使用 XML,当时我的重构书籍出版了。我已经建立了一个网站,并决定添加一个新网站作为关于重构的信息门户。在这个网站上,我列出了我书中所有的重构(以及其他一些),并决定使用 XML 来存储这些重构,这样我希望更容易编辑和更新它们。

总的来说,我发现网站工作有点痛苦。用 HTML 写作很笨拙,尤其是我想进行全局更改或搜索 HTML 文件以获取有用信息时。此外,我无法轻松地为 HTML 和印刷版准备材料。我的梦想一直是能够写出一段文本,可以格式化为 HTML 或良好的印刷形式。当时我手头的工具都没有很好地做到这两点。

我一直是写作中逻辑样式的粉丝。只要我在文字处理器中开始做一些非平凡的事情,我就会设置与我的写作内容结构相匹配的逻辑样式。这样,我可以分别考虑内容和格式 - 尽管如你所见,我的 HTML 格式并不复杂。因此,用 XML 标记文本然后分别格式化为 HTML 的想法对我很有吸引力。

虽然我对重构目录的努力有点粗糙(至少现在看来是这样),但我对整个过程的运作方式非常满意。我用 Framemaker 写书,当时的版本允许以一种原始但有效的方式将框架数据保存为 XML。生成的 XML 还不错,但它并不是我想要的,因为它用 Framemaker 的词汇标记了元素,而不是我想用于网站的标签。幸运的是,XSLT 非常适合解决这个问题,即使我不习惯 XSLT,写一个样式表也很容易,它可以转换我想保留的元素,同时过滤掉我不想要的元素。

一旦我将文件整理好,我就可以编写另一个 XSLT 样式表来将文件显示为 HTML。一个样式表格式化了所有内容,如果我想更改它,我只需要更改一个地方。(DRY 原则是一件好事!)

由于每个文件都是文本化的并且结构良好,我还可以编写一个程序来创建目录索引文件。这是一个 Java 程序,它读取目录中的每个目录文件,并在索引中写入每个重构的选定信息。这样,如果我添加或更改了重构,我只需运行该程序来更新索引。通过将所有这些内容放入 ant 脚本中,我可以通过运行 ant 的构建过程来重新生成整个网站。总的来说,我对整个体验非常满意。

一个网站和一本书

我对重构目录的成功感到高兴,我开始在我的网站上使用 XML 和 XSLT。我开始用 XML 写文章,并将它们转换为 HTML。我喜欢这样做,因为我不必费心处理 HTML 的所有格式代码,我只需用 XML 中的一组简单标签进行写作,让样式表处理剩下的事情。我还可以使用 XSLT 来执行一些任务,例如自动为每篇文章生成目录。

因此,随着 2001 年的推移,我在这种环境中变得越来越熟练,并想出了如何将 XSLT 屈服于我的意志。我意识到,现在可能是用 XML 写作一本书的时候了。到目前为止,我所有的书籍写作都是在 Framemaker 中完成的。Framemaker 有它的缺点,但对我来说,它的优势在于它的稳定性和强大的交叉引用功能。但是,我被它的封闭文件格式所困扰,这往往意味着我无法完成该工具不支持的任务。你也不可能在 Frame 中编写脚本,除非使用昂贵且笨拙的附加软件。然而,对我来说真正的问题是我想将我正在创作的书放到网上,以 HTML 格式呈现,我对 Frame 的转换过程并不满意,当然与 XML/XSLT 相比更是如此。

因此,我开始用 XML 写作我的 P of EAA 书籍,总的来说,我对结果感到满意。不用说,我的下一本书也将用 XML 写作。我发现它不仅对我自己有用,而且在与合著者合作时也有一些技巧很方便,尤其是在 Dave Rice 去了澳大利亚之后。它的优势不在于 XML 本身,而在于 XML 是一种纯文本格式,这为那些与纯文本配合良好的工具打开了大门。

输入文本

人们问的第一个问题似乎是“你用什么来输入文本”。对我来说,答案似乎很明显 - 文本编辑器。作为一个程序员,我对许多文本编辑器都很熟悉,而 XML 作为一种格式的优势之一是你可以使用任何你喜欢的文本编辑器来输入文本。这对合作者来说很棒,因为我不必担心为他们提供昂贵的软件来让他们为这本书贡献他们的部分。

在我写书的时候,我选择的文本编辑器是 TextPad - 毫无疑问是我花在软件上的 30 美元中最值得的。它速度快,并且充满了简单但实用的功能。我发现它的剪辑库非常适合以我想要的方式标记文本。

我考虑过其他 XML 编辑工具,但对各种替代方案并不感兴趣。它们中的大多数都需要 DTD 才能做任何有趣的事情,而我直到游戏后期才开始使用 DTD。

就在最近几个月,我开始使用 XEmacs。多年来我一直断断续续地使用 emacs,但大多数时候都是断断续续的,因为我使用的每台电脑似乎要么没有它,要么就是 Windows 版本对系统其他部分一无所知(我认为剪切和粘贴是基本功能)。Windows 上的 Xemacs 21.4 非常适合 Windows。SGML 主模式非常适合基于文本的文档,尤其是在你拥有 DTD 的情况下 - 我现在有了。当然,你必须习惯 emacs 的键绑定,在如今看来这些键绑定非常复古。

我试过 XML spy 几次,但它并不适合我的目的。它更专注于面向数据的 XML,对于输入文本来说并不那么友好。一旦我习惯了键绑定,我就想念 XEmacs 中那些好用的键绑定。

我将看看未来会发生什么。我当然可以想象一个比简单的文本编辑器更好的工具,但到目前为止,文本编辑器已经击败了一些非常花哨且昂贵的工具。

转换为 HTML

这种方法在生成 HTML 页面时特别有效。用 XML 写作并用 XSLT 转换对我来说非常有效。

一开始并非如此。XSLT 是一种痛苦的语言 - 这是一个很好的理由,说明你为什么不应该将任何基于 XML 的东西用作编程语言。有些人可能会发现它类似 Lisp 的数据/程序相似性很有吸引力。我只是发现它很难编写和使用。它也很复杂,这毫无帮助。

尽管有这些缺点,XSLT 仍然很强大。但有一些技巧可以使你的生活更轻松。

  • 记住,XSLT 就像一门函数式编程语言,它不允许以正常方式使用变量,因此当你想循环时,你使用递归。
  • 用它来匹配模式,而不是驱动输出。因此,更喜欢 <xsl:template match = "foo"> 而不是 <xsl:for-each>。(如果你曾经使用过 awk,你就会更习惯这种方式。)
  • 获取 Michael Kay 的 XSLT Programmer's reference。这是一本令人望而生畏的大书,但它是一本非常好的参考书。它不是学习 XSLT 的最佳书籍,但我发现它在回答详细问题方面非常棒。

为了生成 HTML,实际上在很多其他地方,我依赖于构建脚本。对于这本书,我使用 ant 脚本来自动构建代码和构建书籍页面。拥有一个构建脚本使生活变得更加轻松。

然而,总的来说,我非常喜欢 XML/XSLT 带给我的分离。我发现用一组简单的逻辑标签写作要容易得多,即使我的页面在格式方面非常简单。总有一天,我可能会拥有一个花哨的网站。

转换为印刷版

虽然转换为 HTML 很简单明了,但书籍需要一种印刷样式的格式。这更是一个问题。

我的第一次尝试是使用 XSL-FO 与 apache 的 FOP。在那个时候(2002 年初),我发现虽然 XSL-FO 明显拥有我需要的所有功能,但 FOP 的局限性让我感到沮丧 - 尤其是一本这么大的书。FOP 路线的另一个问题,至少在目前,是出版商还没有准备好。

我认为这些问题是暂时的。随着我们获得更好的 XSL-FO 工具,这将成为生成印刷就绪输出的明显方式。下次我需要生成印刷就绪输出时,我会再次尝试 XSL-FO。

我最终做的是回到我信赖的 Framemaker。我通过从 XML 自动生成 Framemaker 文件来做到这一点。我分两个阶段完成。第一步是 XSLT 转换,它将我用于 P of EAA 的标签转换为与我使用的 Frame 子集相匹配的标签。然后,我使用一个 Ruby 脚本将 Frame 类似的 XML 转换为 Frame 的文本 MIF 格式文件。在第一步中使用 XSLT 在处理转换方面非常有效,但 XSLT 不适合处理 Frame 所需的精确文本格式。XSLT 和 Ruby 的组合完美地发挥了作用。

现在可用于 XML 到印刷的另一个选项是使用 Open Office。Open Office 的文件格式是压缩的 XML,它们非常注重将内容与格式分离。因此,使用 XSLT 来转换内容并在 Open Office 中单独添加格式应该很简单。Microsoft Word 的未来版本也可能会支持这种功能。

图表

我的写作中经常包含图表,尤其是 UML 图表,人们经常问我用什么来绘制图表。我一直避免使用花哨的 CASE 工具,而是选择 Visio - 即使在使用 Visio 时,我也没有使用产品附带的标准 UML 模板。CASE 工具以及 Visio 的 UML 模板的问题在于它们试图变得智能。然而,它们对 UML 的理解远不如普通开发人员,因此这些工具只会妨碍工作。

因此,我使用 Pavel Hruby 开发的一组不同的模板(在我的 链接 页面上查看链接)。

Visio 最令人沮丧的是它在输出方面存在一些恼人的故障。例如,当你输出到 gif 时,结果不太好,经常会切掉图形的最顶行。我期待着浏览器对 SVG 的更多支持,并且可能会在未来尝试 Open Office 的绘图功能,看看它是否能产生更好的结果。

我一开始没有做的一件大事,就是写一个脚本来自动将所有 Visio 图表导出为 gif。我后来才做到了(它会检查 Visio 文件是否在生成相应的 gif 后被修改)。一旦有了这个脚本,生活就轻松多了——幸运的是,Visio 非常容易用几乎任何脚本语言驱动(在我的例子中,是 Ruby)。

自动代码导入

使用这种方案最棒的一点是,它可以自动导入我的示例代码。大多数作者对示例代码都感到头疼,几乎总是会出问题,导致示例代码不一致或无法编译——仅仅是因为保持复制粘贴代码同步的难度。

我能够做得更好。我将所有代码示例保存在目录中,我可以使用 Ant 来构建和测试整个目录。然后,我可以使用带注释的标签标记源代码文件,以标记要导入书籍的代码部分。然后,我编写了一些简单的 Java 代码来快速浏览源文件并生成包含源代码片段的 XML 文件。这些片段随后可以轻松地在我运行 XSLT 时导入输出。这奇妙地消除了原本非常混乱的过程,并让我能够在需要时自信地更改代码示例。

协作和版本控制

我和几个人合作编写了《企业应用架构模式》——最值得注意的是 David Rice,他写了本书的很大一部分。由于我们都在修改文本和代码示例,我们需要仔细协调我们的工作。

答案是 CVS。由于 XML 文件只是文本,CVS 被证明是处理我们协作的完美方式。每当我们修改任何内容时,我们都会将文件上传到 CVS。这变得至关重要,因为我们赶在截止日期前,David 在澳大利亚工作。

当然,CVS 对我个人也很有用。它允许我随时安全地修改文本,因为我知道每个文件的版本历史记录都是可靠的。我们对所有内容都进行了版本控制,包括我们依赖的各种 Java 库和 .NET 程序集。正如程序员应该始终使用版本控制一样,作者也应该这样做!

最后的想法

即使在 XML 相关技术发展的早期,我也发现 XML 是编写大型书籍的非常好的方法。现在,我毫不犹豫地将它用于我几乎所有的写作——包括这篇文章。(主要例外是我写 IEEE 软件专栏时,他们喜欢接收 Word 文件,而且它足够短,所以我不会遇到其他常见的问题。)

如果你想知道是否应该将 XML 用于网站、报告或书籍;如果你是极客并且乐于使用 XSLT、脚本等,我强烈推荐它。如果你不是那么极客,我会建议你等等——但要密切关注支持 XML 的文字处理器。如果新的 Word 真的像传言那样,事情会变得有趣。


重大修订

2003 年 1 月