DocBook 5 快速起步教程

內容概要

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_1 chunk_2
chunk_3 chunk_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_1fop_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_1fop_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文檔中全部都用上,可根據實際需要進行取捨。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章