DocBook 5 快速起步教程

13 篇文章 0 订阅
7 篇文章 0 订阅

内容概要

DocBook是一个写作、排版、出版的利器。本文介绍如何在Mac OS X系统中安装DocBook 5,并使用它来撰写一本简单的书。最后,实现自动生成HTML及PDF文档的目标。

DocBook 5包含了多个版本。目前正式发行版本是V5.0。因此,本文的DocBook 5特指DocBook V5.0版本。

本文知识要点:

  • 使用Catalog部署DocBook
  • DocBook实体的配置及其图表
  • 让NetBeans支持自定义DTD以实现代码自动完成
  • DocBook 5文档的基本结构
  • 使用Bourne-Again shell (bash) 脚本完成HTML及PDF文档的自动生成
  • xlstproc的基本使用方法
  • Safari的webkit
  • 定制DocBook
  • DocBook转换为html, chunk及pdf
  • DocBook中文PDF问题

读者要求

为完全理解本文所讲内容,读者应具备以下前提条件:

  1. 有Mac OS X,版本应在10.6及其以上
  2. 能上网
  3. 具备软件安装权限
  4. 懂得使用NetBeans来打字

读者无需具备HTML、CSS、XML、XSLT、Java、FOP、UNIX命令等相关知识,本文会一步一步的带您完成相关操作。

安装与部署

为方便管理与调用,根据Filesystem Hierarchy Standard以及DocBook 5: The Definitive GuideDocBook XSL: The Complete Guide所推荐的规范,我们将DocBook 5所需的各项资源全部安装到“/usr/share/xml/docbook”路径中。

安装DocBook 5 Schema

DocBook 5支持多种schema。到http://docbook.org/schemas/5x.html下载DocBook 5的schema。下载页面中的当前版本部分见下图所示。

db5_current_release

上图中,分别列出了各种单独的schema。点击“5.0”的链接,在新打开的页面中可看到docbook-5.0.zip文件。该文件包含了所有的schema及相应的文档。下载这个文件。将其解压到“/usr/share/xml/docbook/docbook-5.0”的路径中。

注:默认情况下,Mac OS X的“/usr/share”路径下没有xml的子路径,需要单独创建它。

由于Catalog文件可以简化安装过程,因此我们使用Catalog来部署DocBook。Catalog主要作用体现在三个方面:

  1. 将公共ID与实际网络地址相映射。
  2. 将特定网络地址重新导向至另一个网络地址。
  3. 将网络地址重新导向至本地文件以实现缓存。

DocBook可使用两种catalogs:SGML及XML。由于XML catalog更新、更强,这里讨论使用XML catalog。

在“/usr/share/xml/docbook”路径下创建一个名为“catalog.xml”的文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog"
        prefer="public"
        xml:base="file:///usr/share/xml/docbook/">
    
    <public publicId="-//OASIS//DTD DocBook XML 5.0//EN"
        uri="docbook-5.0/dtd/docbook.dtd"/>
    <system systemId="http://docbook.org/xml/5.0/dtd/docbook.dtd"
        uri="docbook-5.0/dtd/docbook.dtd"/>
    <uri name="http://www.oasis-open.org/docbook/xml/5.0/rng/docbook.rng"
        uri="docbook-5.0/rng/docbook.rng"/>
        
    <uri name="docbook.xsl"
        uri="docbook-xsl-1.76.1/html/docbook.xsl"/>

</catalog>

这样,当处理器查找相应的名称时可优先到所指定的路径中去搜索而无需上网下载。这个catalog.xml文件在下面还要继续修改和完善。

安装字符实体

字符实体可让我们在XML文件中输入一些特定字符,而这些字符将被替换为另外的一些字符甚至符号。XML中预定义了5个字符实体:

  • <   ↔   &lt;
  • >   ↔   &gt;
  • & ↔ &amp;
  • '   ↔   &apos;
  • "   ↔   &quot;

输入右边的字符串,就可得到左边的字符。除了这些预定义的字符实体,我们还可以使用自己的实体。下面作一些简单的介绍(若要详细了解XML的实体,请参见http://www.w3.org/Physical Structures)。

在XML中要使用实体,必须先声明。较为简单的声明如下:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE book PUBLIC '-//OASIS//DTD DocBook XML 5.0//EN' 'null'
[
<!ENTITY author "Sarkuya">
]
>

通过在DOCTYPE的结束标志“>”之前插入一对符号“[]”,然后将要声明的实体放在符号“[]”之间即可。

声明之后,在该XML文档中,只要在需要出现“Sarkuya”的地方,使用“&author;”的标志即可。

我们也可以将所有的实体放在一个外部文件中声明。设有一文件名为“someents.ent”,内容如下所示:

<?xml version="1.0" encoding="UTF-8"?>

<!ENTITY hArr	"&#x21D4;">
<!ENTITY check	"&#x2713;">

这个文件声明了⇔及✓两个符号。在需要使用其的XML文件,可以声明如下:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE book PUBLIC '-//OASIS//DTD DocBook XML 5.0//EN' 'null'
[
<!ENTITY % someents SYSTEM "someents.ent">%someants;
]
>

这种方式声明参数实体。“%”之后“someents”表示实体名称。后面的“someents.ent”表示所引用的文件名称,可以为绝对路径或相对路径方式,上面为相对路径,表明使用它的XML文件与ent文件须放在同一路径下。最后的“%someants;”可理解为立即读取该文件中的所有实体定义。这样,就可在XML文档中输入“&hArr;”来表示⇔,输入“&check;”来表示✓了。

DocBook提供了许多这样的字符实体。可到http://www.oasis-open.org/docbook/xmlcharent/index.shtml下载。之后,在docbook-5.0目录下创建一个“ent”的目录,将这些所有字符实体文件安置到该目录下。关于各类字符实体的符号图表,请参见附录A-字符实体符号表(共有19个,目前已完成2个。由于这些表格太长,完成后,将移至一篇新的文档中以方便参考)。

对于DocBook,我们可以这样声明DocBook的某类实体。

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE book PUBLIC '-//OASIS//DTD DocBook XML 5.0//EN' 'null'
[
<!ENTITY % iso-pub-ent SYSTEM "/usr/share/xml/docbook/docbook-5.0/ent/iso-pub.ent">%iso-pub-ent;
]
>

但这种直接绑定方式并不科学,最好的方法是使用catalog文件来映射。在catalog.xml中添加下面的内容:

<public publicId="iso-pub.ent"
        uri="docbook-5.0/ent/iso-pub.ent"/>

然后,在XML文档中就可以声明:

<!ENTITY % pubents PUBLIC "iso-pub.ent" 'null'>%pubents;

由上,我们可以把所下载的所有的DocBook实体都放在catalog.xml中进行映射。

......
    <public publicId="iso-amsa.ent"
        uri="docbook-5.0/ent/iso-amsa.ent"/>
    <public publicId="iso-amsb.ent"
        uri="docbook-5.0/ent/iso-amsb.ent"/>
    <public publicId="iso-amsc.ent"
        uri="docbook-5.0/ent/iso-amsc.ent"/>
    <public publicId="iso-amsn.ent"
        uri="docbook-5.0/ent/iso-amsn.ent"/>
    <public publicId="iso-amso.ent"
        uri="docbook-5.0/ent/iso-amso.ent"/>
    <public publicId="iso-amsr.ent"
        uri="docbook-5.0/ent/iso-amsr.ent"/>
    <public publicId="iso-box.ent"
        uri="docbook-5.0/ent/iso-box.ent"/>
    <public publicId="iso-cyr1.ent"
        uri="docbook-5.0/ent/iso-cyr1.ent"/>
    <public publicId="iso-cyr2.ent"
        uri="docbook-5.0/ent/iso-cyr2.ent"/>
    <public publicId="iso-dia.ent"
        uri="docbook-5.0/ent/iso-dia.ent"/>
    <public publicId="iso-grk1.ent"
        uri="docbook-5.0/ent/iso-grk1.ent"/>
    <public publicId="iso-grk2.ent"
        uri="docbook-5.0/ent/iso-grk2.ent"/>
    <public publicId="iso-grk3.ent"
        uri="docbook-5.0/ent/iso-grk3.ent"/>
    <public publicId="iso-grk4.ent"
        uri="docbook-5.0/ent/iso-grk4.ent"/>
    <public publicId="iso-lat1.ent"
        uri="docbook-5.0/ent/iso-lat1.ent"/>
    <public publicId="iso-lat2.ent"
        uri="docbook-5.0/ent/iso-lat2.ent"/>
    <public publicId="iso-num.ent"
        uri="docbook-5.0/ent/iso-num.ent"/>
    <public publicId="iso-pub.ent"
        uri="docbook-5.0/ent/iso-pub.ent"/>
    <public publicId="iso-tech.ent"
        uri="docbook-5.0/ent/iso-tech.ent"/>
</catalog>

以后,在需要用到这些实体的XML文档中,则需声明如下:

<!DOCTYPE book PUBLIC '-//OASIS//DTD DocBook XML 5.0//EN' 'null'
[
<!ENTITY % iso-amsa.ent PUBLIC "iso-amsa.ent" 'null'>%iso-amsa.ent;
<!ENTITY % iso-amsb.ent PUBLIC "iso-amsb.ent" 'null'>%iso-amsb.ent;
<!ENTITY % iso-amsc.ent PUBLIC "iso-amsc.ent" 'null'>%iso-amsc.ent;
<!ENTITY % iso-amsn.ent PUBLIC "iso-amsn.ent" 'null'>%iso-amsn.ent;
<!ENTITY % iso-amso.ent PUBLIC "iso-amso.ent" 'null'>%iso-amso.ent;
<!ENTITY % iso-amsr.ent PUBLIC "iso-amsr.ent" 'null'>%iso-amsr.ent;
<!ENTITY % iso-box.ent PUBLIC "iso-box.ent" 'null'>%iso-box.ent;
<!ENTITY % iso-cyr1.ent PUBLIC "iso-cyr1.ent" 'null'>%iso-cyr1.ent;
<!ENTITY % iso-cyr2.ent PUBLIC "iso-cyr2.ent" 'null'>%iso-cyr2.ent;
<!ENTITY % iso-dia.ent PUBLIC "iso-dia.ent" 'null'>%iso-dia.ent;
<!ENTITY % iso-grk1.ent PUBLIC "iso-grk1.ent" 'null'>%iso-grk1.ent;
<!ENTITY % iso-grk2.ent PUBLIC "iso-grk2.ent" 'null'>%iso-grk2.ent;
<!ENTITY % iso-grk3.ent PUBLIC "iso-grk3.ent" 'null'>%iso-grk3.ent;
<!ENTITY % iso-grk4.ent PUBLIC "iso-grk4.ent" 'null'>%iso-grk4.ent;
<!ENTITY % iso-lat1.ent PUBLIC "iso-lat1.ent" 'null'>%iso-lat1.ent;
<!ENTITY % iso-lat2.ent PUBLIC "iso-lat2.ent" 'null'>%iso-lat2.ent;
<!ENTITY % iso-num.ent PUBLIC "iso-num.ent" 'null'>%iso-num.ent;
<!ENTITY % iso-pub.ent PUBLIC "iso-pub.ent" 'null'>%iso-pub.ent;
<!ENTITY % iso-tech.ent PUBLIC "iso-tech.ent" 'null'>%iso-tech.ent;
]
>

尽管字符实体非常实用,但并非所有人都用得到。但如果需要,可返回这里查阅。

安装DocBook样式表

sourceforge的DocBook项目下载DocBook样式表。点击“docbook-xsl”的链接,可看到列出了多个版本,本文写作时最新版本为1.76.1。选择“1.76.1”,Mac OS X平台建议下载docbook-xsl-1.76.1.tar.bz2文件。将其解压到“/usr/share/xml/docbook/docbook-xsl-1.76.1”路径下。

安装XSLT处理器

XSLT处理器包括Saxon、Xalan、xsltproc、XT、MSXML、Sablotron、4XSLT等。由于xsltproc是速度最快的,因此本文选用xsltproc。

Mac OS X中已经自带xsltproc,因此无需再安装。

安装XSL-FO处理器

XSL-FO处理器包括E3、FOP、PassiveTex、Unicorn Formatting Objects、XEP、Xinc、XML2PDF、XML Professional Publisher(XPP)、xmlroff、XSL Formatter等。上述XSL-FO处理器中有许多是商业性的,本文使用基于Java的Apache FOP。

http://www.apache.org/dyn/closer.cgi/xmlgraphics/fop下载FOP。本文写作时最新版本为1.0。Mac OS X下面建议下载fop-1.0-bin.tar.gz。将其解压到“/usr/share/xml/docbook/fop-1.0”路径下。

安装完上面这些工具后,应得到下面的路径设置。

  • /usr
    • share
      • xml
        • docbook
          • catalog.xml [文件]
          • docbook-5.0 [目录]
          • docbook-xsl-1.76.1 [目录]
          • fop-1.0 [目录]

下载并配置NetBeans

NetBeans是一个很实用的免费开源工具,它最初的目的是为Java提供一个编程开发环境。但由于使用DocBook主要是跟XML打交道,而NetBeans的XML编辑功能相当棒,因此本文选择它作为编辑工具。

http://netbeans.org/免费下载NetBeans 7.0.1。我选择的是“All”的下载包。下载后依提示安装即可。

由于DocBook 5向下兼容地提供了DTD,因此我们可以通过配置,让NetBeans支持DocBook 5的格式。

从NetBeans的菜单中选择“工具”->“DTD 和 XML 架构”,在弹出的“DTD 和 XML 架构”窗口中,点击“添加目录(A)...”按钮,在弹出的“添加目录”窗口中,“目录类型”选择“OASIS 目录解析器”,点击“浏览...”按钮,将“file:/usr/share/xml/docbook/catalog.xml”选择至“目录 URL:”文本框中,确认“首选公共 ID”已打上勾,单击“确定”按钮关闭“添加目录”窗口。

nb_add_catalog

在“DTD 和 XML 架构”窗口中,可以看出,catalog.xml已经添加。

nb_catalog_added

这样,在NetBeans中新建“受DTD约束的XML文档”时,在“DTD 公共 ID”栏中可下拉选择“-//OASIS//DTD DocBook XML V5.0//EN”,在“DTD 系统 ID”栏中可填上“http://www.oasis-open.org/docbook/xml/5.0/docbook.dtd”的内容,在“文档根元素”栏中选择“book”,如下图所示:

nb_new_xml

就可生成一个基于以下模板内容的XML文件:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE book PUBLIC '-//OASIS//DTD DocBook XML V5.0//EN'
               'http://www.oasis-open.org/docbook/xml/5.0/docbook.dtd'>

<book>

</book>

因为NetBeans已经通过catalog.xml文件将“-//OASIS//DTD DocBook XML V5.0//EN”与本地DTD文件相联,因此上图中的“DTD 系统 ID”一栏,我们也可不输入任何内容。如果是这样,则NetBeans将生成如下的DOCTYPE:

<!DOCTYPE book PUBLIC '-//OASIS//DTD DocBook XML V5.0//EN'
               'null'>

注意:不要将null去掉,否则,在下面使用xsltproc来生成文档时将无法处理。

虽然DocBook 5不需要使用DOCTYPE,但保留该行,可在NetBeans中实时验证DocBook 5文档的语法,且自动完成DocBook 5的标签的输入,极大地方便了我们在NetBeans中使用DocBook这个强大的工具。

提示:在NetBeans中完成了添加目录的步骤后,我们无需使用NetBeans来生成XML文档。只要在该XML文档上添加上面所述的DOCTYPE的信息,NetBeans就会自动帮助我们完成代码。

使用DocBook编撰我们的第一本书

准备DocBook文档

作为教程,我们的书拟放在用户文档路径中。因此,在“/Users/[user_name]/documents”路径下新建一个“My DocBook Books/My First Book/Content”的路径。并在该目录下新建一个“SampleBook.xml”文档,内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE book PUBLIC '-//OASIS//DTD DocBook XML 5.0//EN' 'null'>

<book xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="zh_cn">
    <title>HTML记要</title>
    <dedication>
        <para>谨以本书献给学习HTML的读者。</para>
    </dedication>
    <chapter>
        <title>HTML概述</title>
        <para>本章简要地讲述了HTML的概况。</para>
        <section>
            <title>何为HTML</title>
            <para>HTML是一个超文本标记语言。</para>
        </section>
        <section>
            <title>HTML的重要性</title>
            <para>如何评估HTML的重要性都不为过。</para>
        </section>
    </chapter>
    <chapter>
        <title>HTML标签</title>
        <para>HTML标签分为很多种。</para>
        <section>
            <title>链接</title>
            <para>HTML的链接标签是<a>。</para>
        </section>
        <section>
            <title>表格</title>
            <para>HTML的链接标签是<table>。</para>
        </section>
    </chapter>
</book>

“My First Book”将作为本教程的主目录。其下面的Content目录专门于用存放书籍内容。另外还有一些其他目录,将在下面介绍。

注意book标签中的xml:lang="zh_cn",这是正确生成中文文档的关键。

DocBook文档结构

此DocBook文档的层级结构图如下所示。

  • book
    • title
    • dedication
      • para
    • chapter
      • title
      • para
      • section
        • title
        • para
    • chapter
      • title
      • para
      • section
        • title
        • para

上面的这篇文档的根元素是book。book下面包含了一个title、一个dedication及两个chapter,分别对应书籍标题、题词及两章。题词下含一个段落。每一章均包含了title、para、section,分别表示章标题、段落、节。section之下又包含了title及para。结构非常清晰。

书名应放在这里,题词内容应放这里,章节内容应放这里。DocBook只关心这个。至于如何排版,现在我们无需关心。这是使用DocBook的好处之一:专心写作,您不必再为排版之事而焦头烂额。至少,在打字时是如此。想想看,我们使用WPS、Word或是Pages来写作时,结果是,大部分的时间都花在了排版上面了。尽管这样,不等于说用DocBook来写的书排版效果就很烂,恰恰相反,使用DocBook写的书,其排版效果是无可堪比的。本文后面部分将带您领略其中的一小部分。

应该说,DocBook提供了非常丰富的标签以充分满足各种书写场合。这些标签都有一定的要求,如书籍的根元素必须为book,dedication只能置于book之下而不能置于其他标签之下,book可以包含多个chapter。这些规则,很难记忆,但如下图所示,NetBeans的自动代码完成功能严格依照DocBook 5的DTD规范,实时地让我们作出正确的选择。

nb_autocomplete

上图中,由于编辑的位置在于book标签之下,NetBeans自动列出了能在book之下使用的所有标签。至于这些标签都各是什么含义,现在无需关心。我们现在只需懂得上面介绍的几个标签:book, title, dedication, chapter, para, section的基本含义,对于本教程来讲,足够了。

将DocBook文档分成多个文档

书籍总会越写越长,将全部内容放在一个XML文档,编辑时会增加不必要的麻烦。一个好的作法是将书籍按章分成多个XML文档。共有2种方法实现。

一种方法是通过上面所谈到的实体声明的方式。

将SampleBook.xml修改如下:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE book PUBLIC '-//OASIS//DTD DocBook XML 5.0//EN' 'null'
[
<!ENTITY chapter1 SYSTEM "chapter1.xml">
<!ENTITY chapter2 SYSTEM "chapter2.xml">
]
>

<book xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="zh_cn">
    <title>HTML记要</title>
    <dedication>
        <para>谨以本书献给学习HTML的读者。</para>
    </dedication>
    &chapter1;
    &chapter2;
</book>

dedication当然也可以分出,但由于其内容比较简短,故可保留在主文档中。

chapter1.xml的内容:

<?xml version="1.0" encoding="UTF-8"?>

<chapter>
    <title>HTML概述</title>
    <para>本章简要地讲述了HTML的概况。</para>
    <section>
        <title>何为HTML</title>
        <para>HTML是一个超文本标记语言。</para>
    </section>
    <section>
        <title>HTML的重要性</title>
        <para>如何评估HTML的重要性都不为过。</para>
    </section>
</chapter>

chapter2.xml的内容:

<?xml version="1.0" encoding="UTF-8"?>

<chapter>
    <title>HTML标签</title>
    <para>HTML标签分为很多种。</para>
    <section>
        <title>链接</title>
        <para>HTML的链接标签是<a>。</para>
    </section>
    <section>
        <title>表格</title>
        <para>HTML的表格标签是<table>。</para>
    </section>
</chapter>

这种方式下,chapter1.xml及chapter2.xml实际上不是一个完整的XML文档,它们不能带有DOCTYPE的声明。在NetBeans中也丧失了XML文档校验及代码自动完成功能。

第二种方法是使用XInclude。此时,SimpleBook.xml的内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE book PUBLIC '-//OASIS//DTD DocBook XML 5.0//EN' 'null'>

<book xmlns="http://docbook.org/ns/docbook"
        xmlns:xi="http://www.w3.org/2001/XInclude"
        version="5.0"
        xml:lang="zh_cn">

    <title>HTML记要</title>
    <dedication>
        <para>谨以本书献给学习HTML的读者。</para>
    </dedication>
    <xi:include href="chapter1.xml"/>
    <xi:include href="chapter2.xml"/>
</book>

chapter1.xml的内容:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE chapter PUBLIC '-//OASIS//DTD DocBook XML 5.0//EN' 'null'>

<chapter xmlns="http://docbook.org/ns/docbook">
    <title>HTML概述</title>
    <para>本章简要地讲述了HTML的概况。</para>
    <section>
        <title>何为HTML</title>
        <para>HTML是一个超文本标记语言。</para>
    </section>
    <section>
        <title>HTML的重要性</title>
        <para>如何评估HTML的重要性都不为过。</para>
    </section>
</chapter>

使用XInclude的好处是,chapter1.xml是一个独立完整的DocBook文档,因此可以带有DTD,也意味着可以充分利用NetBeans的高级编辑功能了。此外,应注意,该文档的根元素已经变成了chapter,且可以带有命名空间。

chapter2.xml的格式完全一致:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE chapter PUBLIC '-//OASIS//DTD DocBook XML 5.0//EN' 'null'>

<chapter xmlns="http://docbook.org/ns/docbook">
    <title>HTML标签</title>
    <para>HTML标签分为很多种。</para>
    <section>
        <title>链接</title>
        <para>HTML的链接标签是<a>。</para>
    </section>
    <section>
        <title>表格</title>
        <para>HTML的表格标签是<table>。</para>
    </section>
</chapter>

生成发布文档

上面我们使用DocBook创建了SampleBook文档及其相关文档,这些文档仅仅是根据DocBook 5的规范通过XML记载了内容,现在,我们需要将其转换为HTML文档及PDF文档。将使用DocBook书写的内容转换成其他形式的文档,既是我们的目的,也是最精彩、最激动人心、最令人热血澎湃的过程。

生成HTML文档

使用DocBook样式表生成HTML文档

我们使用Mac OS X的默认脚本语言Bash来自动生成HTML文档。

打开一个终端,运行以下脚本:

cd /Users/sarkuya/Documents/My\ DocBook\ Books/My\ First\ Book
touch GenHTML.sh
chmod u+x GenHTML.sh

记得将上面的路径换成您的路径。第一行使用“cd”命令将当前路径切换至“My First Book”下面。由于上面的路径名称出现了空格,因此使用“\ ”来转义空格(也可以将整个路径名用半角的""括起来,这样无需转义)。第二行的“touch”命令新建一个空白的“GenHTML.sh”文件,第三行的“chmod”命令将该脚本文件的运行权限赋予当前用户。

在Mac OS X的Finder中将GenHTML.sh文件拖至NetBeans的编辑器窗口中,这样,NetBeans将自动打开并可编辑该文件。输入以下的内容。

#!/bin/bash

export XML_CATALOG_FILES="file:///usr/share/xml/docbook/catalog.xml"
xsltproc --xinclude --output Product/SampleBook.html docbook.xsl Content/SampleBook.xml

因为UNIX系统中允许存在并同时运行多个shell脚本,上面代码的第一行指定了使用Bourne-Again shell。

默认情况下,xsltproc会自动根据环境变量“XML_CATALOG_FILES”的内容在“/etc/xml/catalog”路径下查找catalog.xml文件,因此,如果我们将上面的catalog.xml文件放在“/etc/xml/catalog”的路径下,第二行可以省略。正如上面代码所示,我们可以通过export命令设置环境变量“XML_CATALOG_FILES”从而达到改变默认状态的效果。

代码第三行中,源文件为Content路径下面的SampleBook.xml,套用docbook.xsl所指定的格式后,将在Product路径下面生成SampleBook.html文档。

需注意的是,上面的docbook.xsl是从何而来?我们并未创建此文件。回顾上面创建catalog.xml文件一节的内容,该文件中有一行内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog"
        prefer="public"
        xml:base="file:///usr/share/xml/docbook/">
    
    ......
        
    <uri name="docbook.xsl"
        uri="docbook-xsl-1.76.1/html/docbook.xsl"/>

</catalog>

uri标签将“docbook.xsl”的标识符与“/usr/share/xml/docbook/docbook-xsl-1.76.1/html/docbook.xsl”相映射。这样,当xsltproc遇到“docbook.xsl”的标识符时,便会自动调用后者。这样做的好处是,当以后我们安装了docbook-xsl新的版本,只需修改catalog.xml文件的该行即可。这是使用Catalog来部署的一大好处。

由于在上一节中,我们使用了XInclude,因此,xsltproc需要添加“--xinclude”的参数。并且,在xsltproc中,我们只需指定主干文档SampleBook.xml,而无需指定chapter1.xml或chapter2.xml。

在终端中,在GenHTML.sh文件所在路径下,运行下面的命令:

./GenHTML.sh

在Product路径下面,双击SampleBook.html,您就会看到所生成的SampleBook.html的效果图。

html_with_docbook_stylesheet

可以看出,相对于我们所编写的内容比较简单的SampleBook.xml,这个自动生成的网页为我们提供了一些额外的排版功效:

  • 文章标题下有一条点缀横线。
  • dedication部分加上了题词的标题,chapter部分自动加上了第几章的序号。
  • 分别为全书及各章加上了目录及相应的链接。
  • 分别为标题、内容设置了对应大小的字体。

Oh My God! 这些信手拈来的界面效果,如果让我来排版,真不知从何下手!(边框除外,这是通过用于Safari的wiget - Web Clip实现的)

故事固然精彩,但还远未到结束的时候。我们还可以通过自己的CSS来让这个网页锦上添花。

广告诗词之后,故事更加精彩。:◃)

“使用DocBook, 杜撰内容高深枯涩的文字,你......来! [左手指向对方,边抖,来字顿收。毕恭毕敬]
排版的苦力活,我......来! [拍几下胸脯,延隔了少许秒。义无反顾]
两人联手,天--下--无--贼! [左手作握手姿态,平伸而出,肘微曲;右手五指张开,做朝天而抓状;头仰天。豪气冲天]”

猜猜看,猜猜看,我上面的大鼻子笑脸使用了哪个字符实体?

好,让我们回到演播现场,继续演绎我们精彩的故事。

使用自定义样式表生成HTML

首先,在"My First Book"目录下面新建一个“XSL”目录,并在里面新建一个名为“html.xsl”的文件。内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:import href="/usr/share/xml/docbook/docbook-xsl-1.76.1/html/docbook.xsl" />
    <xsl:param name="html.stylesheet" select="'css/style.css'" />

    <xsl:output method="html" encoding="UTF-8" indent="yes" />

    <xsl:param name="toc.section.depth" select="2" />
    
    <xsl:param name="section.autolabel" select="1" />
    <xsl:param name="section.label.includes.component.label" select="1" />
</xsl:stylesheet>

之前我们使用docbook-xsl来生成HTML文档,没有太多自主权。要调用自定义的CSS,我们需要一个入口。这个入口就是用以取代docbook-xsl的html.xsl。首先,它导入了原来的docbook-xsl作为基础,然后指定了调用css路径下面的style.css文件来继续排版。转换的目标是HTML文件,编码为UTF-8,格式缩进。接着,设置制作目录的级数为2级,章下面的节采用自动编号的形式,且该编号自动包括上级编号。

现在,可以准备CSS文件了。在"My First Book"目录下面新建一个“CSS”目录,并在里面新建一个名为“style.css”的文件。内容如下:

html {
    background: -webkit-gradient(linear, left top, left bottom, from(#00abeb), to(#fff));
}

body {
    background-color: #333;
    margin: 1em;
    padding: 1em;
    -webkit-border-radius: 6px;
    -webkit-box-shadow: 0 0 14px #123;
}

h1.title {
    color: #cb6c8a;
}

h2.title {
    color: #cb6c8a;
}

div.section h2.title {
    color: #82a4bb;
}

p {
    color: #bfbbaf;
    text-indent: 2em;
}

a:link {
    color: #7a8a39;
}

a:hover {
    color: palegreen;
}

body div.titlepage h1.title {
    text-align: center;
}

div.chapter {
    margin-top: 5em;
}

div.chapter h2.title {
    border-bottom: 1px solid grey;
}

div.section h2.title {
    border-bottom-width: 0;
}

div.toc p {
    text-indent: 0;
    color: #ccc;
}

div.toc {
    border: 1px dashed gray;
    padding: 0.5em;
    margin-left: 2em;
}

div.toc dl dd dl {
    margin-top: 0px;
}

下面看到实际网页效果后,再来解释CSS。

接下来,我们修改GenHTML.sh文件的内容。

#!/bin/bash

export XML_CATALOG_FILES="file:///usr/share/xml/docbook/catalog.xml"

rm -r Product
mkdir -p Product/{css,images}
cp CSS/style.css Product/css

xsltproc --xinclude --output Product/SampleBook.html XSL/html.xsl Content/SampleBook.xml

我们的网页不再孤独,它还需要CSS文件,以后可能还需要图片美化。CSS文件及图像文件都需要随同SampleBook.html文件一起发布。因此,我们需要规划Product的内容了。由于Product用于存放自动生成的文档,为避免与上一次的生成结果混在一起,rm命令先将此目录及所有子目录全部删除。之后,在其下面创建了css及images这两个并行的目录。然后,将CSS路径下的style.css复制到Product目录下的css目录下。

xsltproc这次不再调用docbook-xsl,而是调用我们上面所创建的存放于XSL路径下面的html.xsl文件。通过xsltproc,我们把上面所生成的所有文件都组成了一条生产线。

再次运行GenHTML.sh,您将看到以下的效果。

html_with_css

有点像使用iPad 2的感觉吧?呵呵。

在style.css中,我用到了Safari所支持的webkit引擎的圆角及背景色渐变的功能。调色方案使用的是ColorBurn的Troubadour High Score方案。应指出,在编辑CSS过程中需选择各个元素时,我借助于Safari的“检查元素”功能,多快好省地达到了目标。Safari已经成为我目前钟意的浏览器了。

除了界面上与上次不同之外,一个重要的不同之处是章下面的节出现了自动数字序号。这是使用DocBook的一大重要原因:你来写,我来实时编号。

生成由多个网页组成的HTML

目前为止,我们的书确实很短。但如果我们的书很长呢?将一本1000页的书的内容全部放在一个网页中,会不会让读者感到很累?如果能将整本书像连续剧一样分集,只要链接与索引做得好,读者肯定很欢迎。

DocBook支持这种将整本书分成多个单独的网页,并自动在网页间做好相应的链接。我们的书虽短,但有多个章节,可以实现此目标。

在往下走之前,我们先思考2个问题。

  1. 是否需要同时生成单页面的HTML文件及多页面的HTML文件?
  2. 如果需要同时生成,单页面的HTML文件及多页面的HTML文件应否共享CSS及图像?

我的建议是,最好同时生成。且为了发布时方便,不应共享CSS及图像。这样可满足各种不同需求的场合。

我们需要保留原来生成单网页的HTML的指令,但对Product的路径应做适当调整如下。

  • Product
    • pdf
    • html
      • chunk
        • css
        • images
      • single
        • css
        • images

pdf路径为将来生成的PDF文件预留。html分为chunk及single两个路径,分别存放多网页及单网页的HTML文档。这两个路径下面均带有自己的css及images子目录。

现在可以修改GenHTML.sh了。

#!/bin/bash

export XML_CATALOG_FILES="file:///usr/share/xml/docbook/catalog.xml"

rm -r Product
mkdir -p Product/{html/{chunk/{css,images},single/{css,images}},pdf}
cp -r CSS/ Product/html/chunk/css
cp -r CSS/ Product/html/single/css

xsltproc --xinclude --output Product/html/single/SampleBook.html XSL/html.xsl Content/SampleBook.xml

这次的cp命令将CSS路径下面的内容,包括子路径及所有的文件全部复制。注意CSS之后的“/”。在基于GNU的UNIX系统中,不管路径后面是否有“/”,都一样地将该路径及其下面所有路径及文件都复制。而在基于BSD的UNIX系统中,没有“/”,连同该路径一起复制,若有“/”,则只复制其下面的路径和文件,但不包括该路径。Mac OS X是基于FreeBSD及NetBSD的UNIX系统,因此,在cp命令中源路径名后面是否带有“/”含义不一样。由于源路径名是大写的“CSS”,而目标路径名是小写的“css”,显然我们不需要复制源路径本身。因此需要在源路径“CSS”后面加上“/”。

生成多网页的HTML文档的方法并不复杂。将XSL路径下面的html.xsl复制为chunk.xsl,并修改chunk.xsl的内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:import href="/usr/share/xml/docbook/docbook-xsl-1.76.1/html/chunk.xsl" />
    <xsl:param name="html.stylesheet" select="'css/style.css'" />

    <xsl:output method="html" encoding="UTF-8" indent="yes" />

    <xsl:param name="toc.section.depth" select="2" />
    
    <xsl:param name="section.autolabel" select="1" />
    <xsl:param name="section.label.includes.component.label" select="1" />
</xsl:stylesheet>

在GenHTML.sh文件中添加生成多网页的HTML的内容。

......
xsltproc --xinclude --output Product/html/single/SampleBook.html XSL/html.xsl Content/SampleBook.xml
xsltproc --xinclude --output Product/html/chunk/SampleBook.html XSL/chunk.xsl Content/SampleBook.xml

运行GenHTML.sh,在相应路径下检查是否已经同时生成单网页及多网页的HTML,并看看多网页的HTML的效果。

由于原来的CSS的采用了黑色作为背景色,新生成的多网页HTML部分字体偏暗,因此需对style.css做适当修改。

......
a:link, a:visited {
    color: #7a8a39;
}
......
div.navheader table th, div.navfooter table td {
    color: #bfbbaf;
}

再次运行GenHTML.sh,可依序看到下面的页面效果(iPad之后,再送您5个iPhone)。

chunk_1chunk_2
chunk_3chunk_4
chunk_5

“Oh My God!”

“Shut up! Not any more!”

“OK... ... 我的主啊,此乃神作,非人可为也!”

如果查看所生成网页的源代码,就会发现,即使是神作,也是有问题的。一是charset为ISO-8859-1,而不是UTF-8;二是源代码没有自动断行。原来html.xsl中相应的配置对多网页HTML不起作用。修改chunk.xsl的内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:import href="/usr/share/xml/docbook/docbook-xsl-1.76.1/html/chunk.xsl" />
    <xsl:param name="html.stylesheet" select="'css/style.css'" />

    <xsl:param name="chunker.output.encoding" select="'UTF-8'" />
    <xsl:param name="chunker.output.indent" select="'yes'" />

    <xsl:param name="toc.section.depth" select="2" />
    
    <xsl:param name="section.autolabel" select="1" />
    <xsl:param name="section.label.includes.component.label" select="1" />
</xsl:stylesheet>

注意: xsl:param中的select,如果值不是数值型,而是字符串型,需在“”中另加''来括起来。

再查看网页的源代码,问题已经解决。

加入图标

上面生成的HTML由于没有图标,因此还不够生动。docbook-xsl已经内置了几项图标服务:

  • 警示图标,如使用note, tip, warning, caution, important等标签时
  • 导航图标,如上一页,下一页使用的图标
  • 注解说明中出现的数字图标

现在我们开始看看docbook-xsl对警示图标的支持。编辑chapter1.xml,加入以下内容:

......

<chapter xmlns="http://docbook.org/ns/docbook">
    ......
    <section>
        <title>HTML的重要性</title>
        <para>如何评估HTML的重要性都不为过。</para>
        <note>当然是往高评估。</note>
    </section>
</chapter>

为看清新加的内容,修改style.css:

......
div.note {
    color: #999;
    border: 1px solid gray;
}

观察自动生成的ch01s02.html及其源代码,多了“注意”两个字,但没有图标出现。

note_admon_graphics_close

修改chunk.xsl:

......
    <xsl:param name="admon.graphics" select="1" />
</xsl:stylesheet>

上面语句将警示的图标功能打开。重新运行GenHTML.sh,再观察ch01s02.html。

note_admon_graphics_open

两个发现。一个是有了图标的占位符,但没有图标出现。二是尽管我们上面已经修改了style.css中div.note的元素,但字体颜色还是变黑了。如果您使用的浏览器是Safari,用鼠标刷黑“注意”两字,按右键,选“检查元素”,您会发现div.note下面插入了一个table,图标及文字均放在此表中了。

修改style.css:

......
div.note table {
    color: #999;
    border: 1px solid gray;
    width: 100%;
}

放在表格中的内容加上外框后如果太短不美观,因此将其长度调为100%。

再观察生成的源代码中img标签:

<img alt="[注意]" src="images/note.png">

生成的网页期待有一个note.png的图像文件放在images路径下面。到哪找note.png?docbook-xsl已经为我们提供了包括note.png在内的日常所需图标,就放在docbook-xsl-1.76.1/images路径下面。

我们不应仅仅使用docbook-xsl的图标,还应有自己的图片。因此,先在“My First Book”路径下新建一个“IMAGES”目录,用于存放自己创建的图片。这些图片连同docbook-xsl的图标一起,在发布时均要复制到Product的相应路径下面。现在,我们需要重新规划Product下面的路径了。

  • Product
    • html
      • chunk
        • css
        • images
          • custom
          • docbook
      • single
        • css
        • images
          • custom
          • docbook
    • pdf
      • images
        • custom
        • docbook

主要是在各个images路径下面均分为custom及docbook两种,分别存放我们自己创建的和docbook自带的图片。这样的部署,不相混杂,维护方便。另外也为pdf目录做了提前准备。

修改GenHTML.sh:

#!/bin/bash

export DOCBOOK_DIR="/usr/share/xml/docbook"
export XML_CATALOG_FILES="$DOCBOOK_DIR/catalog.xml"
export DOCBOOK_XSL_DIR="$DOCBOOK_DIR/docbook-xsl-1.76.1"

rm -r Product
mkdir -p Product/{html/{chunk/{css,images/{custom,docbook}},single/{css,images/{custom,docbook}}},pdf/images/{custom,docbook}}

cp -r CSS/ Product/html/chunk/css
cp -r CSS/ Product/html/single/css

cp -r IMAGES/ Product/html/chunk/images/custom
cp -r $DOCBOOK_XSL_DIR/images/ Product/html/chunk/images/docbook
cp -r IMAGES/ Product/html/single/images/custom
cp -r $DOCBOOK_XSL_DIR/images/ Product/html/single/images/docbook
cp -r IMAGES/ Product/pdf/images/custom
cp -r $DOCBOOK_XSL_DIR/images/ Product/pdf/images/docbook

xsltproc --xinclude --output Product/html/single/SampleBook.html XSL/html.xsl Content/SampleBook.xml
xsltproc --xinclude --output Product/html/chunk/SampleBook.html XSL/chunk.xsl Content/SampleBook.xml

这次的改动比较大。首先,设置了DOCBOOK_DIR、XML_CATALOG_FILES、DOCBOOK_XSL_DIR等几个环境变量,删除Product目录,按上面规划的路径分别创建目录,再将CSS文件及图像文件分别复制到相应的路径下面。最后两行的xsltproc命令保持不变。

注意DOCBOOK_DIR的设置方式与之前不同了。以前使用“file://”的文件协议方式,这种方式xsltproc可以认识,但cp命令不认识。因此改变路径方式后,双方都能接受。

现在还剩一个问题。如前所述,自动生成的HTML期待着图片在images目录下面,我们改动了这种设置,因此需要将此改动告诉DocBook。同时修改XSL目录下的chunk.xsl及html.xsl文件:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    ......
    <xsl:param name="admon.graphics" select="1" />
    <xsl:param name="admon.graphics.path" select="'images/docbook/'" />
    <xsl:param name="admon.graphics.extension" select="'.png'" />
    <xsl:param name="admon.textlabel" select="0" />
</xsl:stylesheet>

参数admon.graphics.path告诉DocBook,这些警示图片放在“images/docbook/”下面,注意后面必须带有“/”。参数admon.graphics.extension设置为“.png”,DocBook将查找note.png,这是默认设置。可以改为“.gif”,DocBook将查找note.gif。可看看dookbook-xsl的images目录下面都有哪些图标文件。如果需要使用自己创建的图标文件,只需将此规则命名并放在dookbook-xsl的images目录中替换掉原来的就行了。当然还需注意文件尺寸大小问题。

参数admon.textlabel控制应否出现“注意”的标题。这里因美观的原因将其屏蔽掉了。读者可设为“1”值看看效果。

运行GenHTML.sh。

note_admon_label_off

比较好玩,是吧?还有更好玩的。如前所述,还有导航栏的图标呢?因为只有多网页的HTML才需要导航栏,因此,这次只修改chunk.xsl。

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    ......
    <xsl:param name="admon.textlabel" select="0" />

    <xsl:param name="navig.graphics" select="1" />
    <xsl:param name="navig.graphics.path" select="'images/docbook/'" />
</xsl:stylesheet>

chunk_navbar

原理如前所述,只是改由参数navig.graphics及navig.graphics.path来分别控制。

挂上导航图标后,眼球、手感都立即有了不一样的感受,当然还包括幸福指数。

DocBook, do you really know how much I love you?

Shut......

OK, OK......

“您不是说过注解说明中也会有数字图标吗?怎样实现?”

Well, well...那是一个比较较劲的问题,与本文作为一个DocBook快速入门的格调不相符合,会与其他内容组成一个专题,放在另外文章中专述。

好了,自动生成HTML的故事就暂讲到这里。下一节,我们来研究另一个更激动人心的问题 ── 如何自动生成PDF文档。

生成PDF文档

初识FOP

要将DocBook的文档转换为PDF,需经两个步骤,第一步是将DocBook文档转换为.fo文档,第二步再将此.fo文档转换为.pdf文档。FOP甚至可以将此两步合为一步,直接将DocBook文档转换为PDF文档。

对于将DocBook文档转换为.fo文档的第一步,不仅FOP能完成,xsltproc也能完成。由于xsltproc的速度比FOP要快,因此,本文先使用xsltproc转换为.fo文档后,再用FOP将其转换为PDF文档。

修改catalog.xml:

......
<uri name="chuck.xsl"
    uri="docbook-xsl-1.76.1/html/chunk.xsl"/>
<uri name="fop.xsl"
    uri="docbook-xsl-1.76.1/fo/docbook.xsl"/>
......

增加了fop.xsl的引用,供xsltproc调用。

在“My First Book”下面,将GenHTML.sh文件复制为GenPDF.sh文件,修改后者内容如下:

#!/bin/bash

export DOCBOOK_DIR="/usr/share/xml/docbook"
export XML_CATALOG_FILES="$DOCBOOK_DIR/catalog.xml"
export DOCBOOK_XSL_DIR="$DOCBOOK_DIR/docbook-xsl-1.76.1"
export FOP_DIR="$DOCBOOK_DIR/fop-1.0"

clear
xsltproc --xinclude --output Product/pdf/SampleBook.fo --stringparam fop1.extensions 1 fop.xsl Content/SampleBook.xml
$FOP_DIR/fop Product/pdf/SampleBook.fo -awt

xsltproc中的fop.xsl即为刚在catalog.xml中增加的uri名称,因此,它实际调用了docbook-xsl下面的fo/docbook.xsl来将SampleBook.xml转换为SampleBook.fo文件。字符串参数fop1.extensions表示按照FOP所要求的格式来创建。例如,若将fop1.extensions设为1,则生成的PDF文档带有书签。若不设,则PDF文档没有书签。FOP V0.93及其之后版本用此参数,之前的版本用fop.extensions。

$FOP_DIR/fop调用了FOP路径下面的fop这个UNIX可执行文件,该文件负责将上一步生成的SampleBook.fo转换为PDF文档,但选项awt告诉FOP,不生成实际的PDF文档,而是直接显示出来。FOP将打开自带的一个软件来显示所创建的PDF文档。共创建了6页,下面显示的是其中有代表性的两页。

fop_awt_1 fop_awt_2

可以看出,目录部分与正文部分的页码编号采用了不同的数字。但没有节的自动编号,没有警示图标。

创建实实在在的PDF文档

水中望月,雾里观花。一会您就明白为什么了。现在,我们创建真实存在、触手可摸的PDF文档。只需改修改GenPDF.sh的最后一行。

......
$FOP_DIR/fop Product/pdf/SampleBook.fo Product/pdf/SampleBook.pdf

fop_pdf_no_chinese

Oh My God! 这回您不让我叫,我跟您急!Oh My God!

第一个OMG是因为FOP自动生成了漂亮的PDF书签。第二个OMG是因为除了书签,书籍其他地方凡是应该出现中文的地方均出现了“洋文”。

原因说来话长,但长话短说就是,每个系统的字体都不一样,PDF作为一种强调可移植性的文档,正常情况下PDF文件应自带内嵌字体。FOP作为生成PDF的工具,仅自带了14种字体,远远不能满足非英文环境的需求。因此,上面生成的PDF文档在正文中凡是出现中文的地方都因为没有内嵌字体的支持而以“#”号代替。原因明白了,解决的办法也出来了,找到中文字体,嵌到其中就是。

FOP以前要嵌个字体,要自己制作比较繁琐的XML font metrics文件配置。但现在,除了这种方式之外,FOP还支持扫描特定路径的字体,以及查找系统安装字体的方式。本文使用后者。

可能是因为Mac OS X的字体规范的原因,Mac OS X中的很多中文字体不能很好地嵌入PDF文件。因此,本文中只使用到2种字体,一种是黑体,用于标题,另一种是宋体,用于正文等部分。黑体需从Windows中将simhei.ttf复制过来,这是由北京中易中标电子信息技术有限公司设计的,版权归其所有。宋体字则在Mac OS X中已有,且可正常工作,因此用它。

在Mac OS X中双击simhei.ttf,即可安装它,一般是安装到/Users/[your_name]/Library/Fonts下面,但只要安装了,就成了系统字体,而不管其安装路径。

安装完simhei.ttf后,需要让FOP来查找系统字体。在fop-1.0的conf目录下,有一个“fop.xconf”配置文件,做好备份后,将其拖至NetBeans中修改。

......
<renderers>
    <renderer mime="application/pdf">
        ......
        <fonts>
            ......
            <auto-detect/>
        </fonts>
    </renderer>
    ......
</renderers>

只需在fonts标签中加入auto-detect即可。

与生成HTML文档一样,由于我们需要指定字体等定制工作,因此最好有自己的xsl转换文件。在XSL目录下将之前的html.xsl复制为pdf.xsl,并在NetBeans中编辑。

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xml:fo="http://www.w3.org/1999/XSL/Format"
                version="1.0">
    <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl" />
    
    <xsl:include href="sharedparts.xsl" />

    <xsl:param name="title.font.family">SimHei</xsl:param>
    <xsl:param name="body.font.family">SimSun</xsl:param>
    
    <xsl:param name="admon.graphics.path">Product/pdf/images/docbook/</xsl:param>
</xsl:stylesheet>

陌生的内容比较多。xml:fo是定制FO时经常需要用到的,虽然本文用不上,但也在此挂上了。xsl:imprt导入的方式与前面不一样了,这里使用了URI的方式。前面的html.xsl及chunk.xsl均通过绝对路径的方式来导入的,这种硬编码的方式,如果以后使用了新版的docbook-xsl之后不好维护。而使用URI,配合Catalog的配置,可以地实现缓存与维护的两相宜。这里虽然指向了网络地址,但只要在catalog.xml中进行重新导向,xsltproc就能到本地去查找fo/docbook.xsl。为达到此目的,catalog.xml内容修改如下:

<?xml version="1.0" encoding="utf-8"?>

<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog"
        prefer="public"
        xml:base="file:///usr/share/xml/docbook/">
    
    ......
    
    <uri name="fop.xsl"
        uri="docbook-xsl-1.76.1/fo/docbook.xsl"/>
        
    <!-- Rewrite Entries -->
    <rewriteURI
        uriStartString="http://docbook.sourceforge.net/release/xsl/current/"
        rewritePrefix="docbook-xsl-1.76.1/" />
        
    <!-- Referenced Entities -->
    <public publicId="iso-amsa.ent"
        uri="docbook-5.0/ent/iso-amsa.ent"/>
    
    ......

</catalog>

rewriteURI的工作原理是,当发现以uriStartString开始的URI时,将使用经与xml:base整合之后的rewritePrefix的字符串来代替,从而实现将网络地址重新导向到本地文件的缓存效果。这样,pdf.xsl文件中的网络地址上的fo/docbook.xsl文件,实际上被导向至本地目录下了。目前为止,包括配置给NetBeans使用的之内,我们已经使用catalog.xml来实现了4种不同的导向了,读者可慢慢体会。由见可见Catalog在XML应用中的重要性。这样改变了catalog.xml的配置后,之前的html.xsl及chunk.xsl也均可使用了这种缓存机制了。

回到pdf.xsl上。xsl:include插入了一个sharedparts.xsl文件的内容。还记得上面的html.xsl及chunk.xsl的内容吗?有许多内容是一样的,却要多次重复配置。累得不说,如果以后在一个文件中进行了修改,还得在另一个文件中重复相应的修改。很容易忘记进行同步。因此,将相同的部分抽取出来放进一个单独的文件,需要时使用xsl:include包含进来,维护时只在一处修改就好方便。

sharedparts.xsl的内容是什么?看看。

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:param name="toc.section.depth">2</xsl:param>
    
    <xsl:param name="section.autolabel">1</xsl:param>
    <xsl:param name="section.label.includes.component.label">1</xsl:param>
    
    <xsl:param name="admon.graphics">1</xsl:param>
    <xsl:param name="admon.graphics.extension">.png</xsl:param>
    <xsl:param name="admon.textlabel">1</xsl:param>
</xsl:stylesheet>

哈哈,全是上面已经讲过的。由于这些部分,不管是html.xsl,还是chunk.xsl,或是pdf.xsl均要使用,因此就放在此共享文件中了。

html.xsl及chunk.xsl又已经改成什么样了?在此全晾出来。

先是html.xsl的内容。

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl" />
    
    <xsl:include href="sharedparts_html.xsl" />
    
    <xsl:output method="html" encoding="UTF-8" indent="yes" />
</xsl:stylesheet>

xsl:import中也使用了重新导向的缓存机制。只剩下一个其独享的xsl:output了。上面又包含了一个sharedparts_html文件,顾名思义,就是所有的html的xsl文档都应共享的部分,晾完chunk.xsl内容后再晾它。chunk.xsl的内容:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/chunk.xsl" />

    <xsl:include href="sharedparts_html.xsl" />
    
    <xsl:param name="chunker.output.encoding" select="'UTF-8'" />
    <xsl:param name="chunker.output.indent" select="'yes'" />

    <xsl:param name="navig.graphics" select="1" />
    <xsl:param name="navig.graphics.path" select="'images/docbook/'" />
</xsl:stylesheet>

除了shareparts_html.xsl,也均剩下只对chunk起作用的配置了。再看shareparts_html.xsl的内容:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:include href="sharedparts.xsl" />
    
    <xsl:param name="html.stylesheet" select="'css/style.css'" />
    <xsl:param name="admon.graphics.path" select="'images/docbook/'" />
</xsl:stylesheet>

它包含了sharedparts.xsl的内容,剩下的两项,均是对html.xsl及chunk.xsl有效的配置。简而言之,pdf.xsl、html.xsl及chunk.xsl均用得上的配置,放在sharedparts.xsl中,而仅对html.xsl及chunk.xsl起作用的配置,放在sharedparts_html.xsl中,最后,仅对自己有效的配置,则给自己独享。

请原谅我的这种倒插花的讲述方式。在开发过程中进行重构是非常重要而有必要的。这种讲述方式虽在接受知识效果方面略逊一筹,但它讲清了重构前的缺点,重构的过程,以及重构的最终效果,读者不仅得到了最终的成果,也从中体会到了重构的魅力及必要的技巧。

不再倒插花了,再次回到pdf.xsl上来。title.font.family指定了标题使用SimHei,即黑体字,body.font.family使用SimSun,即宋体字。运行Mac OS X中的字体册程序,点击已经安装的字体,其Postscript名称就是SimHei及SimSun的由来。

pdf.xsl虽像html.xsl及chunk.xsl一样,均共同使用admon.graphics.path,但其查找方式与另外二者不一致,是由FOP来根据GenPDF.sh的路径作为起始点来查找的,因此这项配置专门放在了pdf.xsl中。

好,繁琐的配置终于完成,开始发指令了。修改GenPDF.sh:

#!/bin/bash

export DOCBOOK_DIR="/usr/share/xml/docbook"
export XML_CATALOG_FILES="$DOCBOOK_DIR/catalog.xml"
export DOCBOOK_XSL_DIR="$DOCBOOK_DIR/docbook-xsl-1.76.1"
export FOP_DIR="$DOCBOOK_DIR/fop-1.0"

clear
rm Product/pdf/*.fo Product/pdf/*.pdf

# xsltproc --xinclude \
#     --output Product/pdf/SampleBook.fo \
#     --stringparam title.font.family "SimHei" \
#     --stringparam body.font.family SimSun \
#     --stringparam admon.textlabel 1 \
#     --stringparam admon.graphics 1 \
#     --stringparam admon.graphics.path "Product/pdf/images/docbook/" \
#     --stringparam header.rule 1 \
#     --stringparam fop1.extensions 1 \
#     fop.xsl \
#     Content/SampleBook.xml

xsltproc --xinclude \
    --output Product/pdf/SampleBook.fo \
    --stringparam fop1.extensions 1 \
    XSL/pdf.xsl \
    Content/SampleBook.xml

$FOP_DIR/fop -c $FOP_DIR/conf/fop.xconf Product/pdf/SampleBook.fo Product/pdf/SampleBook.pdf

中间以“#”开始的部分被注释掉了,不会执行,在此说明很多参数都可以放在xsltproc的命令行中设置,与在pdf.xsl中设置的结果一样,但内容多了以后,还是建议放在pdf.xsl中设置。最后一行的fop,选项c指定了使用上面修改的fop.xconf文件中的配置来生成PDF,这样就可把查找到的字体嵌进来。

运行GenPDF.sh。

fop_pdf_i18n_1 fop_pdf_i18n_2

长征路漫漫,总差一步半。枝头幸运鸟,何时来伴伴。

宋体字一切正常。目录的黑体字正常。但章节部分,在应出现空格的地方,出现了“#”号。还有一个特点,即出现错误的地方,都是有自动生成内容的部分。看来是在转换文档的过程中,在需要生成新内容的地方,使用了不该使用的字符。此外,“1.1.”不规范,应为“1.1 ”。我不是事后诸葛亮,解决这些问题总会花去大量的时间,现在,求求您就让我迫不及待地直接告诉您答案吧。修改pdf.xsl文件:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xml:fo="http://www.w3.org/1999/XSL/Format"
                version="1.0">
    ......
    
    <xsl:param name="local.l10n.xml" select="document('')"/>
    <l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0">
        <l:l10n language="zh_cn">
            <l:context name="title-numbered">
                <l:template name="chapter" text="第 %n 章 %t"/>
                <l:template name="section" text="%n %t"/>
            </l:context>
        </l:l10n>
    </l:i18n>
</xsl:stylesheet>

local.l10n.xml专管本地化的工作。读取文档后,对于自动生成编号的标题,在chapter及section部位,输入符合需求的内容。%n代表数字,%t代表标题。之间的空格,采用最原始的暴力输入——使用键盘上的空格键。看来制作docbook-xsl的专家,这个老美的键盘一定是特制的。

fop_pdf_normal

谢幕,黯然退场。

参考资源

  1. Filesystem Hierarchy Standard, by Rusty Russell, Daniel Quinlan, Christopher Yeoh, Filesystem Hierarchy Standard Group:http://www.pathname.com/fhs/pub/fhs-2.3.html
  2. DocBook 5: The Definitive Guide V1.0.3 for DocBook V5.0, by Norman Walsh, XML Press:http://www.docbook.org/tdg5/en/html/docbook.html
  3. DocBook XSL: The Complete Guide 4th Ed. by Bob Stayton, Sagehill Enterprises:http://www.sagehill.net/docbookxsl/index.html
  4. Apache FOP 字体配置, The Apache XML Graphics Project: http://xmlgraphics.apache.org/fop/1.0/fonts.html
  5. List of Unix utilities, Wikipedia: http://en.wikipedia.org/wiki/List_of_Unix_programs
  6. xsltproc命令行参数, xmlsoft.org: http://xmlsoft.org/XSLT/xsltproc.html
  7. XML 1.0 Recommendation, World Wide Web Consortium (W3C): http://www.w3.org/TR/2008/REC-xml-20081126/
  8. w3schools.com: http://www.w3schools.com/
  9. Entity Declarations, Attributes and Expansion, by Norman Walsh, O'REILLY xml.com:http://www.xml.com/pub/a/98/08/xmlqna2.html
  10. HTML Paramter Refernce, DocBook XSL Stylesheets: Reference Documentation, by Norman Walsh, The DocBook Project:http://docbook.sourceforge.net/release/xsl/current/doc/html/
  11. Fo Paramter Refernce, DocBook XSL Stylesheets: Reference Documentation, by Norman Walsh, The DocBook Project:http://docbook.sourceforge.net/release/xsl/current/doc/fo/

附录

附录A 字符实体符号表 [进度:7 / 19]

iso-amsa.ent [56个表示关系的箭头符号]
实体名称实体符号
cularr
curarr
dArr
darr2
dharl
dharr
lAarr
Larr
larr2
larrhk
larrlp
larrtl
lhard
lharu
hArr
harr
lrarr2
rlarr2
harrw
rlhar2
lrhar2
lsh
map
mumap
nearr
nlArr
nlarr
nhArr
nharr
nrarr
nrArr
nwarr
olarr
orarr
rAarr
Rarr
rarr2
rarrhk
rarrlp
rarrtl
rarrw
rhard
rharu
rsh
drarr
dlarr
uArr
uarr2
vArr
varr
uharl
uharr
xlArr
xhArr
xharr
xrArr

iso-amsb.ent [42个表示二进制操作符的符号]
实体名称实体符号
amalg
Barwed
barwed
Cap
Cup
cuvee
cuwed
diam
divonx
intcal
lthree
ltimes
minusb
oast
ocir
odash
odot
ominus
oplus
osol
otimes
plusb
plusdo
rthree
rtimes
sdot
sdotb
setmn
sqcap
sqcup
ssetmn
sstarf
timesb
top
uplus
wreath
xcirc
xdtri
xutri
coprod
prod
sum
iso-amsc.ent [9个表示分界的符号]
实体名称实体符号
rceil
rfloor
rpargt
urcorn
drcorn
lceil
lfloor
ulcorn
dlcorn

iso-amsn.ent [59个表示不等的数学符号]
实体名称实体符号
gnap
gne
gnE
gnsim
gvnE
lnap
lnE
lne
lnsim
lvnE
nap
ncong
nequiv
ngE
nge
nges
ngt
nle
nlE
nles
nlt
nltri
nltrie
nmid
npar
npr
npre
nrtri
nrtrie
nsc
nsce
nsim
nsime
nsmid
nspar
nsub
nsube
nsubE
nsup
nsupE
nsupe
nvdash
nvDash
nVDash
nVdash
prnap
prnE
prnsim
scnap
scnE
scnsim
subne
subnE
supne
supnE
vsubnE
vsubne
vsupne
vsupnE

iso-amso.ent [18个数学符号]
实体名称实体符号
ang
angmsd
beth
bprime
comp
daleth
ell
empty
gimel
image
inodotı
nexist
oS
planck
real
sbsol
vprime
weierp

iso-amsr.ent [84个表示关系的数学符号]
实体名称实体符号
ape
asymp
bcong
bepsi
bowtie
bsim
bsime
bump
bumpe
cire
colone
cuepr
cuesc
cupre
dashv
ecir
ecolon
eDot
esdot
efDot
egs
els
erDot
fork
frown
gap
gsdot
gE
gel
gEl
ges
Gg
gl
gsim
Gt
lap
ldot
lE
lEg
leg
les
lg
Ll
lsim
Lt
ltrie
mid
models
pr
prap
pre
prsim
rtrie
samalg
sc
scap
sccue
sce
scsim
sfrown
smid
smile
spar
sqsub
sqsube
sqsup
sqsupe
ssmile
Sub
subE
Sup
supE
thkap
thksim
trie
twixt
vdash
Vdash
vDash
veebar
vltri
vprop
vrtri
Vvdash

iso-box.ent [40个画边框线的符号]
实体名称实体符号
boxh
boxv
boxur
boxul
boxdl
boxdr
boxvr
boxhu
boxvl
boxhd
boxvh
boxvR
boxhU
boxvL
boxhD
boxvH
boxH
boxV
boxUR
boxUL
boxDL
boxDR
boxVR
boxHU
boxVL
boxHD
boxVH
boxVr
boxHu
boxVl
boxHd
boxVh
boxuR
boxUl
boxdL
boxDr
boxUr
boxuL
boxDl
boxdR

符号很多,不可能在一个XML文档中全部都用上,可根据实际需要进行取舍。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值