Archive for April, 2011

8 年后重拾 DocBook

2011-4-19 22:01 | by 2ndboy

  最近 blog 更新实在是少,因为很多心得都直接进 wiki 了,其中一些可以在整理成熟后拿到 blog 里来做个总结,但是另外一些内容天生就更合适呆在 wiki 里。今天把最近研究 DocBook 的心得拿出来晒晒。

  记得是从 WorldHello 上知道 DocBook 这个好东西的,那时大概是 2003 年左右,当时貌似国内研究这个东西的人不多,而且一些相关的工具也不是太成熟,所以几经周折后也没有搭出来可以顺利工作的环境,后来也就没有继续研究下去了。去年把 wiki 翻出来用上以后,效果不错,所以前段时间又抽时间研究了一下 DocBook 这个同样在数年前曾经研究过一下的好东西。8 年间,光阴荏苒,DocBook 的主流已经不再是 SGML,而是变成了 DocBook 5.0 的 XML,相关的工具也更加成熟。下面就整理一下最近的学习成果,给出在 Windows 平台下搭建 DocBook 编译环境的方法,还有如何把 DocBook 源文件转换成包括 PDF 在内的各种常用格式的方法。

DocBook 介绍

  简单的讲,DocBook 是一种撰写文档(书籍、论文)的格式规范,它是 XML 的一种“方言”,只用来表达文档的结构性和内容,至于文档要被显示成什么样子,那是跟 DocBook 所配合的 XSL 和 processor 来决定的,有点像 HTML 跟 CSS 的关系。

  所以,用 DocBook 来写文档,你要按照 DocBook 的约定,用你喜欢的文本编辑器(当然也可以是有专门定制 GUI 的 tool)来编辑一个 XML 文件。当你想要把这个文档的内容放在网上供访客浏览的时候,就可以用 processor 把这个 DocBook 源文件转换成 HTML 格式;或者你想要分发或者打印这个文件的时候,你可以用 processor 把同一份 DocBook 源文件转换成 PDF 格式。

  这样做的好处在于:

  • 文本格式的文档方便进行 diff 和版本控制
  • 同一份源文档可以通过不同的处理方法得到各种格式的输出格式
  • 不会因为某种文件格式的过时而不能打开文档
  • 可以很方便的编辑,源文件内容可读
  • 方便进行本地化

  当然坏处也显而易见,DocBook 有一定的学习成本,不过比起它的好处来,这点成本可以忽略不计。目前有很多开源软件的文档和专业电子书都是用 DocBook 写成的,所以你会发现在看某些软件文档或者电子书的时候,同样的内容,经常会提供不同格式文件的下载,这一般都是通过 DocBook 来实现的。

环境需求

  要用 DocBook 来写文档,并且把它转换成你需要的格式,你需要这样一些东西:一个顺手的文本编辑器(比如 VimNotepad++ 或者 Emacs)、DocBook 的 XSL stylesheets 还有 XSLT processor 和 XSL-FO processor。

语法 & 编辑器

  文本编辑器就不用说了,操起你最习惯的就可以了。当然,你得先学习一下 DocBook 的语法,这里推荐一下权威的免费电子书《DocBook 5: The Definitive Guide》,你也可以在i18n-zh 的 Google Code 主页找到一个中译版本,不过已经许久不更新了。

DocBook XSL stylesheets

  接下来你可以到 DocBook Project 在 SourceForge 的页面下载最新版的 DocBook XSL stylesheets,我们把 DocBook 源文件转换到其它格式全靠它了!推荐下载 docbook-xsl-ns,它跟 docbook-xsl 的区别在于,docbook-xsl-ns 可以处理带有 namespace 的 DocBook 源文件(带有 namespace 的 DocBook 是 DocBook 5.0 的 new feature)。我写这篇文章的时候 docbook-xsl-ns 的最新版本是 1.76.1。假设你下载以后把它解压至 C:\DocBook\docbook-xsl-ns-1.76.1。

XSLT processor

  XSLT processor 用来根据 XSL 把 XML 格式的 DocBook 源文件转换成其它格式(比如 HTML 格式或者 .fo 格式(Format Objects,转换成 PDF 之前的中间格式))。在这里下载 xsltproc 的 for Windows 版,你一共需要下载 4 个包:iconv,libxml2,libxslt 和 zlib。假设你下载后把它们解压至 C:\DocBook\win32。

XSL-FO processor

  XSL-FO processor 用来把 XSL formatting objects 格式转换成 PDF 等格式。这里我们使用来自 Apache 软件基金会的 FOP。它目前的最新版本是 1.0。假设你下载以后把它解压至 C:\DocBook\FOP。

示例 DocBook 文件

  目前为止,我们的 DocBook 编译环境就已经搭好了,下面给出一个 DocBook 示例文件,把它保存成 C:\DocBook\2ndboy.xml,我们下面的内容都使用这个示例文件做例子:

  1. <?xml version='1.0' encoding="utf-8"?>
  2.  <article xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="zh-CN"
  3.      xmlns:xlink='http://www.w3.org/1999/xlink'>
  4.      <articleinfo>
  5.          <title>大标题</title>
  6.          <author>
  7.              <firstname></firstname>
  8.              <surname></surname>
  9.          </author>
  10.      </articleinfo> 
  11.      <section>
  12.          <title>标题</title>
  13.          <para>
  14.              这是我的第一篇Docbook 5.0文档,欢迎你来到<link xlink:href='http://blog.2ndboy.net/'>2ndboy 的 Blog</link>
  15.          </para>
  16.      </section>
  17.  </article>

DocBook to PDF

  如果是用来转换全英文的 DocBook 源文件,以上准备已经 OK 了,但是为了可以处理中文的 DocBook,还需要以下两个步骤:

让 FOP 自动识别并使用系统字体

  首先要让 FOP 可以找到并使用系统自带的字体(主要是中文字体)。把下面两行内容放到 C:\DocBook\FOP\conf\fop.xconf 里面的 <renderer mime=“application/pdf”><fonts> 节点里:

  1. <directory recursive="true">C:\Windows\Fonts</directory>
  2.  <auto-detect/>

第一句是指定字体文件的存放位置,并且递归搜索子目录。第二句是让 FOP 自动检测字体。

定制 PDF 的转换效果

为了控制转换后得到的 PDF 文件的最终效果(纸张类型,边距,字体等),我们需要定制一下用于转换过程中的 XSL stylesheet,只需要在之前下载的官方 XSL stylesheet 的基础上重载一些参数即可。把下面 XML 内容保存成 C:\DocBook\pdf.xsl:

  1. <?xml version='1.0'?>
  2.  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  3.      xmlns:exsl="http://exslt.org/common"
  4.      xmlns:fo="http://www.w3.org/1999/XSL/Format"
  5.      xmlns:ng="http://docbook.org/docbook-ng"
  6.      xmlns:db="http://docbook.org/ns/docbook"
  7.      exclude-result-prefixes="db ng exsl"
  8.      version='1.0'>
  9.  
  10.      <xsl:import href="file:///C:/DocBook/docbook-xsl-ns-1.76.1/fo/docbook.xsl"/>
  11.  
  12.      <xsl:param name="body.font.family">SimSun</xsl:param>
  13.      <xsl:param name="body.font.size">12</xsl:param>
  14.      <xsl:param name="monospace.font.family">Consolas</xsl:param>
  15.      <xsl:param name="title.font.family">SimHei</xsl:param>
  16.      <xsl:param name="page.margin.inner">2cm</xsl:param>
  17.      <xsl:param name="page.margin.outer">2cm</xsl:param>
  18.      <xsl:param name="hyphenate">true</xsl:param>
  19.      <xsl:param name="paper.type" select="'A4'"/>
  20.      <xsl:param name="draft.mode" select="'no'"/>
  21.      <xsl:param name="fop1.extensions" select="1"/>
  22.  </xsl:stylesheet>

这里值得一提的是“fop1.extensions”这个参数,设成 1 以后可以生成有书签的 PDF 文件。

转换方法

把 DocBook 源文件转换成 PDF 格式需要分两步,首先把 XML 源文件转换成 .fo 格式:

cd C:\DocBook
win32\bin\xsltproc --encoding utf-8 -o 2ndboy.fo pdf.xsl 2ndboy.xml

然后再把 .fo 文件转换成 PDF 格式:

FOP\fop -c FOP\conf\fop.xconf -fo 2ndboy.fo -pdf 2ndboy.pdf

其实这两个步骤也可以直接通过 FOP 一步完成:

FOP\fop -c FOP\conf\fop.xconf -xsl pdf.xsl -xml 2ndboy.xml -pdf 2ndboy.pdf

只不过这样你就没办法调试 .fo 文件了。

DocBook to RTF

RTF(Rich Text Format)格式的文件可以用 Word 和写字板打开,也是一种常用的格式。把 DocBook 转成 RTF 格式同样需要两步:

win32\bin\xsltproc --encoding utf-8 -o 2ndboy.fo pdf.xsl 2ndboy.xml
FOP\fop -c FOP\conf\fop.xconf -fo 2ndboy.fo -rtf 2ndboy.rtf

为了方便我们这里直接使用了上面转换 PDF 时定制过的 XSL 文件。

DocBook to PNG

DocBook 文件还可以直接转成图片,比如常见的 PNG(Portable Network Graphics)格式,这里同样是两个步骤,为了偷懒同样直接使用我们用来转换 PDF 的那个 XSL 文件:

win32\bin\xsltproc --encoding utf-8 -o 2ndboy.fo pdf.xsl 2ndboy.xml
FOP\fop -c FOP\conf\fop.xconf -fo 2ndboy.fo -png 2ndboy.png

DocBook to HTML

用 DocBook 生成 HTML 输出有两种选择,一种是把所有内容放在一个单独的 HTML 文件里,另外一种是每一章节一个单独的 HTML 文件(就是所谓的 chunk HTML)。

生成单页 HTML

为了让生成的 HTML 文件不把汉字编码成 HTML 转义形式(比如 &#65288;),我们这里也需要重载一下用于 HTML 转换的 XSL 文件,下面内容另存为 C:\DocBook\html.xsl:

  1. <?xml version='1.0' encoding="utf-8"?>
  2.  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  3.      xmlns:exsl="http://exslt.org/common"
  4.      xmlns:fo="http://www.w3.org/1999/XSL/Format"
  5.      xmlns:ng="http://docbook.org/docbook-ng"
  6.      xmlns:db="http://docbook.org/ns/docbook"
  7.      exclude-result-prefixes="db ng exsl"
  8.      version='1.0'>
  9.  
  10.      <xsl:import href="file:///C:/DocBook/docbook-xsl-ns-1.76.1/html/docbook.xsl"/>
  11.  
  12.      <xsl:output method="html" encoding="UTF-8" indent="no"/>
  13.  </xsl:stylesheet>

转换命令行如下:

win32\bin\xsltproc --encoding utf-8 --nonet -o 2ndboy.html html.xsl 2ndboy.xml

生成 chunk HTML

想要生成 chunk HTML 也需要重载 XSL,把下面内容另存为 C:\DocBook\chunkhtml.xsl:

  1. <?xml version='1.0' encoding="utf-8"?>
  2.  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  3.      xmlns:exsl="http://exslt.org/common"
  4.      xmlns:fo="http://www.w3.org/1999/XSL/Format"
  5.      xmlns:ng="http://docbook.org/docbook-ng"
  6.      xmlns:db="http://docbook.org/ns/docbook"
  7.      exclude-result-prefixes="db ng exsl"
  8.      version='1.0'>
  9.  
  10.      <xsl:import href="file:///C:/DocBook/docbook-xsl-ns-1.76.1/html/chunk.xsl"/>
  11.  
  12.      <xsl:param name="chunker.output.encoding" select="'UTF-8'"/>
  13.  </xsl:stylesheet>

转换命令行如下:

win32\bin\xsltproc --encoding utf-8 --nonet -o 2ndboy.html chunkhtml.xsl 2ndboy.xml

生成的多个 HTML 文件会自动重命名。

DocBook to ePub

随着各种平板和电子阅读器的日渐流行,ePub 这种小屏幕友好的电子读物格式标准也越来越流行了,其实 DocBook 也可以被很方便的转换到 ePub 格式。我们重载一下 XSL,把下面内容另存为 C:\DocBook\epub.xsl:

  1. <?xml version='1.0'?>
  2.  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  3.      xmlns:exsl="http://exslt.org/common"
  4.      xmlns:fo="http://www.w3.org/1999/XSL/Format"
  5.      xmlns:ng="http://docbook.org/docbook-ng"
  6.      xmlns:db="http://docbook.org/ns/docbook"
  7.      exclude-result-prefixes="db ng exsl"
  8.      version='1.0'>
  9.  
  10.      <xsl:import href="file:///C:/DocBook/docbook-xsl-ns-1.76.1/epub/docbook.xsl"/>
  11.  
  12.      <xsl:param name="body.font.family">SimSun</xsl:param>
  13.      <xsl:param name="monospace.font.family">Consolas</xsl:param>
  14.      <xsl:param name="title.font.family">SimHei</xsl:param>
  15.      <xsl:param name="hyphenate">true</xsl:param>
  16.      <xsl:param name="draft.mode" select="'no'"/>
  17.      <xsl:param name="fop1.extensions" select="1"/>
  18.  </xsl:stylesheet>

转换命令如下,为了方便,我把它写成了批处理。把下面内容另存为 C:\DocBook\epub.bat:


@echo off
win32\bin\xsltproc --encoding utf-8 epub.xsl %1.xml
echo.|set /P ="application/epub+zip" > mimetype
zip -0Xq %1.epub mimetype
zip -Xr9D %1.epub META-INF
zip -Xr9D %1.epub OEBPS
del /q/a/f/s META-INF\*.*
rmdir META-INF
del /q/a/f/s OEBPS\*.*
rmdir OEBPS
del mimetype

如果你想把 test.xml 转换成 test.epub,只需要在 C:\DocBook\ 下执行“epub test”即可。由于简单的讲,ePub 可以被看成是把一堆 XHTML 打包在一个 zip 压缩包里,所以这里用到了 zip,Windows 下的 zip 移植版可以在 gunwin32 下载。

有待解决的问题

目前还有些问题有待解决:

  1. 虽然 FOP 1.0 支持指定字体集,比如“<xsl:param name=”body.font.family”>Verdana,SimSun</xsl:param>”,但是这样写以后发现很多混杂在中文里的英文还是宋体,没法做到完美混合!
  2. 没法做到自动在中英文间插入一个空隙,中英文紧挨在一起,不好看,难道只能人肉插空格?

希望过路高手留言:)

[2011/7/29]:增加了 DocBook to ePub 的内容