## 第 27 章 docbook 指南
**目录**
[](ch27.html#id3123080)
[XML 简介](ch27s02.html)
[XML 语法](ch27s03.html)
[标记](ch27s03.html#id3123193)
[元素](ch27s03.html#id3123262)
[处理指令](ch27s03.html#id3123298)
[文件头部](ch27s03.html#id3123327)
[实体](ch27s03.html#docbook-entity)
[DocBook 介绍](ch27s04.html)
[搭建 DocBook 环境](ch27s05.html)
[创建 DocBook 文档](ch27s06.html)
[结构元素](ch27s07.html)
[文档信息](ch27s08.html)
[分子元素](ch27s09.html)
[块元素](ch27s10.html)
[行内元素](ch27s11.html)
[特殊字符](ch27s12.html)
[列表](ch27s13.html)
[Callout 列表](ch27s13.html#id3125171)
[表格](ch27s14.html)
[跨行表格](ch27s14.html#id3125603)
[跨列表格](ch27s14.html#id3125784)
[链接](ch27s15.html)
[内部链接](ch27s15.html#docbook-ln)
[外部链接](ch27s15.html#id3126103)
[脚注](ch27s15.html#id3126172)
[参考](ch27s15.html#id3126216)
[告示](ch27s16.html)
[图形](ch27s17.html)
[文档工程](ch27s18.html)
[DocBook 编辑软件](ch27s19.html)
[发布](ch27s20.html)
[使用 CSS 定制外观](ch27s21.html)
[代码块的样式](ch27s21.html#id3127629)
[简单表格的样式](ch27s21.html#id3127710)
[技巧](ch27s22.html)
[关于表格](ch27s22.html#id3127854)
[交叉引用](ch27s22.html#id3127875)
[calloutlist 自动编号问题](ch27s22.html#id3127890)
[断行符](ch27s22.html#db-linebreak)
[内部链接](ch27s22.html#id3127988)
## XML 简介
在学习 DocBook 之前,我们需要先了解一下 XML,因为 DocBook 是 XML 的一个 DTD(文档类型定义)
XML 是一种被设计用来存储、交换数据的通用标记语言
为了使它更加的通用,XML 的元标记不具有意义,XML 使用 DTD 赋予某一组标记特定的意义
为了便于自动处理,它只包含内容而不包含样式定义,XSL 便是这样一种自动处理的机制,它将根据特定规则将 XML 转换为可以定义样式的格式
Html 语言不具备以上特点,我们用它对比说明,一份完整的 Html 文档就是由许多这样的标记嵌套而成:
```
<html>
<head>头部</head>
<body>
<p>这是一个段落,这里是 <b>粗体</b> </p>
</body>
</html>
```
* Html 语言的标记,都有具体的意义,像 `<p>` 表示这是一个段落
* Html 语言的标记,还可以直接定义内容的样式。比如加粗某处文字,使用标记 `<b>粗体</b>`。
`<b>`是开始标记,它告诉浏览器,从这个标记开始,后面内容用粗体显示;
`</b>`是结束标记,它告诉浏览器,粗体显示到这里结束
由于 Html 语言的标记都有具体的意义,都和网页显示有关,所以它也只能用来显示网页。如果在 DTD 中定义 `<b> <p>` 这些标记的意义,XML 也可以显示网页(xhtml)
假设有一段文字,里面提到一个文件名和一个软件名,由于 Html 的标记指定的是样式而不是内容,作为变通,我们可以使用粗体来表示它们,但是不能准确的区分它们。而 XML 定义的是内容,把它们分别定义为 filename 和 application,然后通过 XSL 给它们指定不同的样式,便可以很容易的区分
## XML 语法
### 标记
XML 使用 `< >` 来定义标记
所有的 XML 标记必须结束。`<para>`必须有一个与之配对的`</para>`;或者使用空标记,例如`<para/>`
XML 标记大小写敏感。`<para>`和`<PARA>`是两个不同的标记;在 Docbook 中,所有的标记都是小写的
标记必须正确的嵌套,不允许相互嵌套
```
<section><para></section></para> 错误
<section><para></para></section> 正确
```
### 元素
XML 使用开始标记和结束标记来定义元素。例如`<para>段落</para>`;或者使用空标记,例如`<xref linkend="ln"/>`
元素可以带有一个或多个属性,也可以不带属性。属性值必须加引号,例如`<para id="p1">`
### 处理指令
使用`<? ?>`括起来,例如:`<?linebreak?>`插入一个断行符[参见](ch27s22.html#db-linebreak "断行符")
### 文件头部
```
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE article
PUBLIC "-//OASIS//DTD DocBook XML V4.5/zh_cn" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s03.html#docbook09) 处理指令
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s03.html#docbook11) XML 的版本是1.0
> [![3](https://box.kancloud.cn/2015-10-12_561bcb94ee26f.png)](ch27s03.html#docbook12) 文档的编码是 UTF-8
> [![4](https://box.kancloud.cn/2015-10-12_561bcb9508b82.png)](ch27s03.html#docbook10) 开始声明 DTD(文档类型定义)
> [![5](https://box.kancloud.cn/2015-10-12_561bcb95133e7.png)](ch27s03.html#docbook13) 声明文档的根元素是 article
> [![6](https://box.kancloud.cn/2016-01-06_568cdb4f32753.png)](ch27s03.html#docbook15) 公共标识
> [![7](https://box.kancloud.cn/2016-01-06_568cdb4f41fcc.png)](ch27s03.html#docbook14) 系统标识
### 实体
给内容指定一个名称,通过名称引用。引用时以`&`起始,`;`结束。
这样定义一个实体
```
<!ENTITY x "XML">
```
输入`&x;`,XML 会用 `XML` 替换它
以上是内部实体,可以通过定义外部实体来引用外部文档
```
<!ENTITY docbook SYSTEM "docbook.xml">
```
输入`&docbook;`,会将`docbook.xml`文件中的内容插入到当前位置
内部实体和外部实体都是普通实体,只能够在 DTD 中定义
```
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5/zh_cn"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
[
<!ENTITY x "XML">
<!ENTITY docbook SYSTEM "docbook.xml">
]>
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s03.html#docbook21) 这里声明 DTD 的方法是引用外部 DTD
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s03.html#docbook22) 自己定义的实体为内部 DTD
* 内部 DTD 的定义优先于外部 DTD,如果你定义的实体外部 DTD 中已包含,引用时使用的是你自己的定义
有一些特殊字符不能直接插入 XML 中,例如`<`、`&`、`空格字符`[[50](ch27s03.html#ftn.id3123601)],使用`<`、`&`、` `[[51](ch27s03.html#ftn.id3123623)]输入这些字符
* * *
> [[50](ch27s03.html#id3123601)] 不管有多个空格,XML 都认为只有一个
> [[51](ch27s03.html#id3123623)] 它们预先定义在外部 DTD 中
参见`/usr/share/xml/docbook/xml-dtd-4.5/ent/isonum.ent`
## DocBook 介绍
前面已经讲了,DocBook 是 XML 的一个 DTD[[52](ch27s04.html#ftn.id3123652)]。
DocBook 主要用来写文档,尤其适合写科技文档。
* 尽管它的语法不如 reStructuredText 之类文档语言简明清晰,但是它的表现能力足够强大
* 它的结构控制能力十分强悍,对于大型的文档工程,DocBook 几乎是不二的选择
* DocBook 足够通用,它已经成为一种事实上的标准,可以生成多种格式的文档,并为多种文档工具所支持,它特别适合作为原始文档来生成其它格式文档
* * *
> [[52](ch27s04.html#id3123652)] 它相当庞大,有400个左右的标记;当然常用的也就几十个
## 搭建 DocBook 环境
在 Linux 系统中,DocBook 环境主要由以下几个软件包提供
| | |
| --- | --- |
| libxml2 | XML 解析器 |
| docbook-xml | DocBook 的 DTD 定义 |
| libxslt | XSL 转换程序![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png) |
| docbook-xsl | 用来处理 DocBook-XML 的样式表 |
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s05.html#docbook-01) xsltproc 这个转换程序就在这个软件包中
> 还有两个 JAVA 的转换程序 saxon、 xalan,不推荐
例如,在 Archlinux 中可以这样安装:
```
sudo pacman -S docbook-xml docbook-xsl libxslt libxml2
```
## 创建 DocBook 文档
这是一个最基本的 Docbook 文档
```
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE article
PUBLIC "-//OASIS//DTD DocBook XML V4.5/zh_cn" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<article>
<info>
<title>文章</title>
<author>作者</author>
<address>地址</address>
<copyright><year>2008</year><holder>所有者</holder></copyright>
</info>
<sect1>
<title>标题</title>
<para>
内容
</para>
</sect1>
</article>
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s06.html#docbook-create01) 文件头,其实不需要深入的了解它,因为它的变动通常很小
留意一下系统支持的 DocBook DTD 最高版本**ls /usr/share/xml/docbook**
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s06.html#docbook-create02) 文档的根元素,要紧跟文件头
> [![3](https://box.kancloud.cn/2015-10-12_561bcb94ee26f.png)](ch27s06.html#docbook-create03) 文档信息
> [![4](https://box.kancloud.cn/2015-10-12_561bcb9508b82.png)](ch27s06.html#docbook-create04) 文档主体,[“分子元素”一节](ch27s09.html "分子元素")中详细介绍
将上面代码保存为`docbook.xml,`试着[发布](ch27s20.html "发布")
## 结构元素
DocBook 中的一些元素,在发布的时候会作为条目被收进目录。它们表示的是文档内部的结构,所以它们是结构元素,如下:
```
<set>
<book>
<part>
<chapter>
<sect1>
<sect2>
…………
</sect2>
</sect1>
</chapter>
</part>
</book>
</set>
```
如果 DocBook 的根元素是**article**,那么可以允许这种结构:
```
<article>
<sect1>
<sect2>
…………
</sect2>
</sect1>
</article>
```
* 结构元素可以拥有标题,**title**、**titleabbrev**、**subtitle**任选一个,还可以拥有**info**
可以看出,无论是 Book 还是 Article,自 **sect1**[[53](ch27s07.html#ftn.id3124008)]而下的结构都是相同的。
如果把**sect1**元素的内容放在一个单独的文件中,那么无论是 Book 还是 Article 都可以不加改动的引用这个文件,参见[“文档工程”一节](ch27s18.html "文档工程")
以下是常用的结构元素
| 元素 | 说明 |
| --- | --- |
| set | 集 |
| book | 书 |
| part | 部 |
| chapter | 章 |
| article | 文章 |
| sections | 节 |
* * *
> [[53](ch27s07.html#id3124008)] section 与 sect1、sect2……sect5 的区别在于,section 可以无限嵌套,sect1 到 sect5 只能逐级嵌套
> 推荐使用 sect1~5,这样可以使文档的结构更加清晰,而且通常5级也够用了;如果超过5级,那样的文章估计也没法读
## 文档信息
**info**跟在根元素之后,用来放置一些文件信息
```
<info>
<title>文章</title>
<author>作者</author>
<address>地址</address>
<copyright><year>2008</year><holder>所有者</holder></copyright>
</info>
```
## 分子元素
DocBook 最基本的元素是 **para** 和块元素,比它们大的是结构元素,比它们小的是行内元素。
| 元素 | 说明 |
| --- | --- | --- |
| sect1 | 节 | ![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png) |
| section | 节 | ![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png) |
| para | 段落 | ![3](https://box.kancloud.cn/2015-10-12_561bcb94ee26f.png) |
| formalpara | 带标题段落 | ![4](https://box.kancloud.cn/2015-10-12_561bcb9508b82.png) |
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s09.html#dbk21) sect1-5逐级嵌套
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s09.html#dbk22) 可无限嵌套
> [![3](https://box.kancloud.cn/2015-10-12_561bcb94ee26f.png)](ch27s09.html#dbk23) 简单段落
> [![4](https://box.kancloud.cn/2015-10-12_561bcb9508b82.png)](ch27s09.html#dbk24) 复杂段落,可以带标题
**section**其实属于结构元素,它的标题会被收录到目录中。把它们放在这里,因为它们是放进单独文件的最佳元素
## 块元素
块元素是和**para**同级的元素,它们比较复杂,后面会分别介绍
| 类别 | 元素 | 说明 |
| --- | --- | --- |
| 列表 | calloutlist |
| bibliolist | 书目列表 |
| glosslist | 词汇列表 |
| itemizedlist | 无序列表 |
| orderedlist | 有序列表 |
| segmentedlist | 成分列表 |
| simplelist | 简单列表 |
| variablelist | 定义列表 |
| 告示 | caution | 小心 |
| important | 重要 |
| note | 注意 |
| tip | 提示 |
| warning | 警告 |
| 文本 | address | 地址 |
| literallayout | 纯文本 |
| programlisting | 代码 |
| screen | 文本抓屏 |
| synopsis | 命令、函数纲要 |
| 例子,图片和表格 | example |
| informalexample |
| figure |
| informalfigure |
| table |
| informaltable |
| 媒体文件 | audioobject | 音频对象 |
| imageobject | 图片对象 |
| imageobjectco | 带 callout 的图片对象 |
| videoobject | 视频对象 |
| textobject | 文本对象 |
| 其他 | blockquote | 引用 |
| epigraph | 题记 |
| msgset | 有关的错误信息 |
| sidebar | 侧边栏 |
## 行内元素
假如你想用特殊的格式表示诸如短语、用户输入、命令、软件、文件,尽量不要使用 emphasis(强调),它们有专门的元素来表示。
尽管使用了这些元素,得到的效果可能和强调一样是粗体,而且还要考虑使用哪种类型,比较麻烦。
不过等到你想用红色表示命令、绿色表示文件……,这个时候,如果你一直用的是 emphasis,你将会为你的草率付出代价。
| 元素名 | 含义 | 示例 |
| --- | --- | --- |
| abbrev | 略写,一般后面带有一个点('.') | <abbr class="abbrev">abbrev</abbr> |
| emphasis | 强调 | _强调_ |
| phrase | 短语 | 短语 |
| quote | 用引号引起来 | “用引号引起来” |
| trademark | 注册商标 | 注册商标™ |
| literal | 文字的字面含义 | `文字的字面含义` |
| prompt | 提示符 | `提示符` |
| userinput | 用户输入 | `用户输入` |
| subscript | 下标 | <sub>下标</sub> |
| superscript | 上标 | 上标 |
| application | 软件名 | 软件名 |
| command | 命令 | **命令** |
| envar | 环境变量 | `环境变量` |
| filename | 文件名 | `文件名` |
| database | 数据库 | 数据库 |
| email | 电子邮件 | `<[电子邮件](mailto:%E7%94%B5%E5%AD%90%E9%82%AE%E4%BB%B6)>` |
## 特殊字符
一些字符在 XML 中有特殊的含义,只能够通过其实体名称输入
| 字符 | 写法 | 缩写涵义 |
| --- | --- | --- |
| < | < | less than |
| > | > | greater than |
| & | & | ampersand |
| " | " | quote |
| ' | ' | apostrophe |
| 空格 | | none-break space |
* 通常需要使用实体输入的字符包括`<`、`&`、`空格`
XML 会将任意数量的空格解析为一个,如果想通过多个空格控制缩进,就要使用` `
`]]>`这个字符序列也不能直接输入,这样输入它`]]>`
也可以不使用实体输入特殊字符,通过**CDATA**直接引用:
```
<![CDATA[ `<&` ]]>
```
## 列表
最普通的列表为无序列表和有序列表:
```
<itemizedlist>
<listitem>
列表项内容,可以使用**para**、**formalpara**等
</listitem>
</itemizedlist>
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s13.html#docbook-li-01) 无序列表;有序列表为**orderedlist**,每个项自动编号
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s13.html#docbook-li-02) 列表项
词汇列表
词汇列表每一项包括一个词汇标题和词汇定义,标题粗体,定义缩进。这本身就是一个词汇列表
```
<glosslist>
<glossentry>
<glossterm>词汇标题</glossterm>
<glossdef>
<para>词汇定义</para>
</glossdef>
</glossentry>
</glosslist>
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s13.html#docbook-li-11) 词汇列表
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s13.html#docbook-li-12) 列表项
> [![3](https://box.kancloud.cn/2015-10-12_561bcb94ee26f.png)](ch27s13.html#docbook-li-13) 词汇标题
> [![4](https://box.kancloud.cn/2015-10-12_561bcb9508b82.png)](ch27s13.html#docbook-li-14) 词汇定义
> [![5](https://box.kancloud.cn/2015-10-12_561bcb95133e7.png)](ch27s13.html#docbook-li-15) 词汇定义必须为**para**元素
### Callout 列表
在引用的代码块中加记号,并在外部注释。如果你要解释一个比较复杂的概念,**calloutlist**通常是最好的选择
```
<screen>
这里会有一个数字`1`<co id="1"/>的记号
它就是 callout <co id="2"/>
</screen>
<calloutlist>
<callout arearefs="1">这里是记号`1`的说明</callout>
<callout arearefs="2">第二个记号的说明</callout>
</calloutlist>
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s13.html#docbook-cl01) 使用`<co id="1"/>`作记号
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s13.html#docbook-cl03) 第二个记号
> [![3](https://box.kancloud.cn/2015-10-12_561bcb94ee26f.png)](ch27s13.html#docbook-cl04) calloutlist 列表,每一个项都用数字编号
> [![4](https://box.kancloud.cn/2015-10-12_561bcb9508b82.png)](ch27s13.html#docbook-cl02) callout 元素作为解释,使用`arearefs=""`引用
## 表格
表格更适合用可视化方式来生成;因为它有两个维度,使用线性的标记语言来生成,自然比较麻烦。
DocBook 生成表格虽然麻烦,但是相对 reStructuredText 等使用空间方位生成的方式,却更容易控制
表格分为两种**table**和**informaltable**,区别在于**table**可以有标题,能够被收录到目录中。下面是表格的实例:
**表 27.1. 表格实例**
| | 表头 |
| --- | --- | --- |
| | 表底 |
| 单元格一 | 单元格二 | 单元格三 |
| 11 | 12 | 13 |
| | 22 | 23 |
| 31 | | |
```
<table>
<title>表格实例</title>
<tgroup cols="3">
<thead><row><entry></entry><entry>表头</entry></row></thead>
<tfoot><row><entry></entry><entry></entry><entry>表底</entry></row></tfoot>
<tbody>
<row>
<entry>单元格一</entry>
<entry>单元格二</entry>
<entry>单元格三</entry>
</row>
<row>
<entry>11</entry>
<entry>12</entry>
<entry>13</entry>
</row>
<row>
<entry></entry>
<entry>22</entry>
<entry>23</entry>
</row>
<row>
<entry>31</entry>
</row>
</tbody>
</tgroup>
</table>
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s14.html#docbook-table01) 说明使用的是何种表格,**table**还是**informaltable**
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s14.html#docbook-table02) 表格标题
> [![3](https://box.kancloud.cn/2015-10-12_561bcb94ee26f.png)](ch27s14.html#docbook-table03) 定义表格宽度(有多少列),必需!
> [![4](https://box.kancloud.cn/2015-10-12_561bcb9508b82.png)](ch27s14.html#docbook-table04) 表头,表格的第一行,用粗体显示,非必需
> [![5](https://box.kancloud.cn/2015-10-12_561bcb95133e7.png)](ch27s14.html#docbook-table05) 表底,其实我从来没见过有人用它
> [![6](https://box.kancloud.cn/2016-01-06_568cdb4f32753.png)](ch27s14.html#docbook-table06) 表体,表格的主体部分
> [![7](https://box.kancloud.cn/2016-01-06_568cdb4f41fcc.png)](ch27s14.html#docbook-table07) 行,每一行可以拥有的单元格不能超过表格宽度的定义
> [![8](https://box.kancloud.cn/2016-01-06_568cdb4f5948a.png)](ch27s14.html#docbook-table08) 单元格。**entry**元素的内容从该行第一格开始排列
> [![9](https://box.kancloud.cn/2016-01-06_568cdb4f68749.png)](ch27s14.html#docbook-table09) 第一格留空的话,要用`<entry></entry>`占一个位置
> [![10](https://box.kancloud.cn/2016-01-06_568cdb4f83cf0.png)](ch27s14.html#docbook-table10) 留空的单元格之后没有 有内容的单元格,可以省略`<entry></entry>`
### 跨行表格
**表 27.2. 跨行表格**
| | |
| --- | --- |
| 跨两行 | 12 | 13 |
| 22 | 23 |
| 31 | 跨三行 | 33 |
| 41 | 跨两行 |
| 51 |
```
<table>
<title>跨行表格</title>
<tgroup cols="3">
<tbody>
<row>
<entry morerows="1">跨两行</entry><entry>12</entry><entry>13</entry>
</row>
<row>
<entry>22</entry><entry>23</entry>
</row>
<row>
<entry>31</entry><entry morerows="2">跨三行</entry><entry>33</entry>
</row>
<row>
<entry>41</entry><entry morerows="1">跨两行</entry>
</row>
<row>
<entry>51</entry>
</row>
</tbody>
</tgroup>
</table>
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s14.html#docbook-table21) 使用`morerows="N"`合并下方的N个单元格;
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s14.html#docbook-table22) 由于该行第一个单元格已经被合并,所以应在这里出现的**entry**元素取消
> [![3](https://box.kancloud.cn/2015-10-12_561bcb94ee26f.png)](ch27s14.html#docbook-table23) 这里有一个**entry**被取消
> [![4](https://box.kancloud.cn/2015-10-12_561bcb9508b82.png)](ch27s14.html#docbook-table24) 这里有两个**entry**被取消
### 跨列表格
**表 27.3. 跨列表格**
| | |
| --- | --- |
| 第一个单元格 | 第三个单元格 | 第四个单元格 |
| 第一个单元格 | 第二个单元格 |
| 第一个单元格 | 第二个单元格 | 第三个单元格 | 第四个单元格 |
```
<table>
<title>跨列表格</title>
<tgroup cols="4">
<colspec colnum="1" colname="1"/>
<colspec colnum="2" colname="2"/>
<colspec colnum="3" colname="3"/>
<colspec colnum="4" colname="4"/>
<tbody>
<row>
<entry namest="1" nameend="2">第一个单元格</entry><entry>第三个单元格</entry><entry>第四个单元格</entry>
</row>
<row>
<entry>第一个单元格</entry><entry namest="2" nameend="4">第二个单元格</entry>
</row>
<row>
<entry>第一个单元格</entry><entry>第二个单元格</entry><entry>第三个单元格</entry><entry>第四个单元格</entry>
</row>
</tbody>
</tgroup>
</table>
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s14.html#docbook-table31) 先给每列取个名
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s14.html#docbook-table32) 列编号
> [![3](https://box.kancloud.cn/2015-10-12_561bcb94ee26f.png)](ch27s14.html#docbook-table33) 列名。可以任意取,但为了清晰,我用编号作为列名
> [![4](https://box.kancloud.cn/2015-10-12_561bcb9508b82.png)](ch27s14.html#docbook-table34) 跨列单元格的起始列,用列名指定
> [![5](https://box.kancloud.cn/2015-10-12_561bcb95133e7.png)](ch27s14.html#docbook-table35) 跨列单元格的结束列
## 链接
### 内部链接
转到[内部链接](ch27s15.html#docbook-ln "内部链接")
```
<sect1 id="target">被链接章节</sect1>
转到<link linkend="target">被链接章节</link>
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s15.html#docbook-ln01) 给被链接的部分指定一个 id
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s15.html#docbook-ln02) 给**link**元素添加**linkend**属性,指向刚才定义的 id
> [![3](https://box.kancloud.cn/2015-10-12_561bcb94ee26f.png)](ch27s15.html#docbook-ln03) **link**元素内容为链接文字
如果想更精细的控制跳转的目标,可以设置锚点
```
这里是一个锚点<anchor id="anchor"/>
点击跳转到<link linkend="anchor">锚点</link>
```
点击跳转到[锚点](ch27s15.html#anchor)
### 外部链接
访问[linuxtoy.org](http://linuxtoy.org)
```
访问<ulink url="http://linuxtoy.org">linuxtoy.org</ulink>
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s15.html#docbook-ln11) 协议不能省略
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s15.html#docbook-ln12) 外部地址
> [![3](https://box.kancloud.cn/2015-10-12_561bcb94ee26f.png)](ch27s15.html#docbook-ln13) 链接文字
### 脚注
这是脚注<sup>[[54](ch27s15.html#ftn.id3126178)]</sup>的写法
```
<para>这是脚注<footnote><para>脚注示例</para></footnote>的写法</para>
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s15.html#docbook-ln21) 脚注内容必须为**para**元素或块元素
### 参考
参考[“内部链接”一节](ch27s15.html#docbook-ln "内部链接")
```
参考<xref linkend="docbook-ln"/>
```
* * *
> [[54](ch27s15.html#id3126178)] 脚注示例
## 告示
告示往往比较有用,它的使用很简单:
```
<note>note</note>
<tip>tip</tip>
<caution>caution</caution>
<important>important</important>
<warning>warning</warning>
```
> 注意:note
> 提示:tip
> 小心:caution
> 重要:important
> 警告:warning
## 图形
插入图形的方法
![](https://box.kancloud.cn/2016-08-07_57a6a93581b95.png)
```
<graphic fileref="img/warning.png"/>
<imagedata fileref="img/warning.png"/>
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s17.html#docbook-image) DocBook DTD 5.0 将统一使用**imagedata**
使用**figure**作为图形的父元素可以进行编号
**图 27.1. **
![](https://box.kancloud.cn/2016-08-07_57a6a93581b95.png)
```
<figure>
<imagedata fileref="img/warning.png"/>
</figure>
```
## 文档工程
如果你在作一个比较大的文档,建议每个章节使用一个单独的文件存储,便于管理[[55](ch27s18.html#ftn.id3126372)]
前面讲到的[实体](ch27s03.html#docbook-entity "实体")可以用来作这件事情
有两个文件一个是主文件`docbook.xml`,包含文件头和文档信息;另一个文件`file.xml`是文档内容,主文件如下:
```
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5/zh_cn"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
[
<!ENTITY file SYSTEM "file.xml">
]>
<article>
<info></info>
&file;
</article>
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s18.html#docbook-project01) 定义外部实体
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s18.html#docbook-project02) 通过外部实体引用文档
`file.xml`文件内容如下:
```
<sect1>
<para>
……
</para>
</sect1>
```
* 参见[“分子元素”一节](ch27s09.html "分子元素")
如果把引用文件的列表放在外部文件中,则更加容易管理。但是 XML 不允许在 DTD 中引用普通实体[[56](ch27s18.html#ftn.id3126489)],这就要定义参数实体:
```
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5/zh_cn"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
[
<!ENTITY % list SYSTEM "list.xml">
%list;
]>
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s18.html#docbook-project11) 在定义参数实体时,这里多了一个`%`
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s18.html#docbook-project12) 引用参数实体时使用`%`而不是`&`
`list.xml`文件内容如下:
```
<!ENTITY file SYSTEM "file.xml">
<!ENTITY file1 SYSTEM "file1.xml">
<!ENTITY file2 SYSTEM "file2.xml">
```
这样就可以在正文引用`list.xml`文件中定义的普通实体了
* * *
> [[55](ch27s18.html#id3126372)] 即便文档规模不是很大,把内容独立出来也有好处,比如:
> 每部分单独发布,修改,节省时间
> 如果出错便于排查
> [[56](ch27s18.html#id3126489)] 在 DTD 中能够定义外部文件作为普通实体,但是只能在正文中引用,不能在 DTD 中引用
## DocBook 编辑软件
我使用 Emacs 编辑 DocBook 源文件,使用`docbook-xml-mode.el`这个扩展,在`.emacs`文件中加入下面配置:
```
;---------- Docbook
(require 'docbook-xml-mode)
(add-hook 'docbook-xml-mode-hook
(function (lambda ()
(setq outline-regexp "<!\\-\\-\\*+")
(outline-minor-mode)
(hide-body))))
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s19.html#docbook-edit01) 加载 docbook-xml-mode
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s19.html#docbook-edit02) 添加 docbook-xml-mode 钩子,运行下面代码
> [![3](https://box.kancloud.cn/2015-10-12_561bcb94ee26f.png)](ch27s19.html#docbook-edit03) 将`<!--*`识别为大纲标识
> [![4](https://box.kancloud.cn/2015-10-12_561bcb9508b82.png)](ch27s19.html#docbook-edit04) 启动大纲模式作为辅模式
> [![5](https://box.kancloud.cn/2015-10-12_561bcb95133e7.png)](ch27s19.html#docbook-edit05) 隐藏所有内容,只显示主干
关于大纲模式的使用参见[Emacs 大纲模式](ch25s17.html "大纲模式")
Emacs 还有一个 `nxml-mode.el` 也可以用来编写 DocBook,它的优点是可以自动完成 DTD 验证,有语法方面的错误能够实时提示,但是对于多文件的工程支持不够好;而且它插入 XML 标记是通过自动补全,不如 `docbook-xml-mode.el` 方便,DTD 验证和语法检查其实可以由 xsltproc 完成,所以我不用它。
还有一些工具可以生成 docbook-xml 的源文件,如 Emacs-muse,但毕竟不够灵活;通过语法简单的 muse 源文件生成语法复杂的 docbook-xml,所能拥有的特性不会超出 muse 的表现范围,不能够利用 DocBook 强大的能力
## 发布
使用xsltproc将它发布为 Html
```
xsltproc /usr/share/xml/docbook/xsl-stylesheets-1.73.2/html/html.xsl docbook.xml
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s20.html#docbook-publish-01) xsl-stylesheets目录,里面包含可以发布的格式。该路径可能会因系统的不同而改变
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s20.html#docbook-publish-02) 发布为 Html 格式所需要的 xsl 文件
> [![3](https://box.kancloud.cn/2015-10-12_561bcb94ee26f.png)](ch27s20.html#docbook-publish-03) 发布为单独的 html 页面。如果需要分页,使用`chunk.xsl`
这是最简单的发布。有的时候,我们需要进行一些控制,例如使用 CSS、设定输出目录等,可以在命令中加入参数:
```
xsltproc --output ../html/ \
--stringparam html.stylesheet docbook.css \
/usr/share/xml/docbook/xsl-stylesheets-1.73.2/html/html.xsl \
docbook.xml
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s20.html#docbook-publish-11) 设定输出目录
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s20.html#docbook-publish-12) 使用 CSS 样式表
> [![3](https://box.kancloud.cn/2015-10-12_561bcb94ee26f.png)](ch27s20.html#docbook-publish-13) 使用 XSL 样式表
这个命令有点长,我们可以把相关参数写入参数样式表`param.xsl`,使用命令**xsltproc param.xsl docbook.xml**发布
下面是一个参数样式表的例子,复制保存:
**例 27.1. DocBook 参数样式表**
```
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!--调用样式表-->
<xsl:import href="/usr/share/xml/docbook/xsl-stylesheets-1.73.2/html/chunk.xsl"/>
<xsl:param name="chunker.output.encoding" select="'utf-8'"/>
<!--标准信息所使用的语言-->
<xsl:param name="l10n.gentext.language" select="'zh_cn'"/>
<!--指定样式表-->
<xsl:param name="html.stylesheet" select="'docbook.css'"/>
<!--对于警告类信息是否使用图形 0 1-->
<xsl:param name="admon.graphics" select="1"/>
<!--生成的 HTML 文件存放的起始目录-->
<!--如果没有在 Makefile 或命令中指定,取消这里的注释
<xsl:param name="base.dir" select="'../html/'"/>
-->
<!--生成的 HTML 文件内容是否进行缩排 yes no-->
<xsl:param name="chunker.output.indent" select="'yes'"/>
<!--给节编号 0 1-->
<xsl:param name="section.autolabel" select="0"/>
<!--节的编号是否包含章的编号 0 1-->
<xsl:param name="section.label.includes.component.label" select="1"/>
<!--表格边框的属性是否使用预设 CSS 来指定-->
<xsl:param name="table.borders.with.css" select="0"/>
<!--参考书目是否进行编号-->
<xsl:param name="bibliography.numbered" select="1"></xsl:param>
<!--目录深度-->
<xsl:param name="toc.max.depth" select="2"/>
<!--sect#页面上显示目录-->
<xsl:param name="generate.section.toc.level" select="0"/>
<!--sect#可以生成目录条目-->
<xsl:param name="toc.section.depth" select="2"/>
<!--目录中收录哪些内容-->
<!--包括 toc,title,figure,table,example,equation -->
<!-- nop 为空 -->
<xsl:param name="generate.toc">
appendix toc
article/appendix nop
article toc,title
book toc,title,example
chapter toc,title
part toc,title
preface toc,title
qandadiv toc
qandaset toc
reference toc,title
sect1 toc
sect2 toc
sect3 toc
sect4 toc
sect5 toc
section toc
set toc,title
</xsl:param>
<!--在源码中插入 <?linebreak?> 标记,生成 Html 时替换为<br> -->
<xsl:template match="processing-instruction('linebreak')">
<br/>
</xsl:template>
</xsl:stylesheet>
```
将偷懒进行到底,使用下面 `Makefile`,在工作目录下键入**make**就可以了[[57](ch27s20.html#ftn.id3127148)]
```
OBJECT = all
SOURCE = docbook.xml
PARAM = param.xsl
ARG = --output html/
COMPILER = xsltproc
$(OBJECT):$(SOURCE) $(PARAM)
$(COMPILER) $(ARG) $(PARAM) $(SOURCE)
clean:
rm -rf ../html/*.html
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s20.html#docbook-mf) 这里一定要用 TAB,而不能用空格字符
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s20.html#docbook-mf1) 同上
* * *
> [[57](ch27s20.html#id3127148)] 在 Emacs 中 **M-x compile** 效果更好,如果有错误还能够直接定位
## 使用 CSS 定制外观
DocBook 输出为 Html 时,如果不使用 CSS 控制,那么它的外观将比较“朴素”
如果自己写一个 CSS 未免太麻烦,可以随便找一个 DocBook 写的文档,将里面的 CSS 文件拿来修改[[58](ch27s21.html#ftn.id3127223)]
通过例子简单介绍下 CSS
```
body {
font-family: verdana, tahoma, helvetica, arial, sans-serif;
text-align: left;
background: #fff;
color: #222;
margin: 1em;
padding: 0;
font-size: 1em;
line-height: 1.2em
}
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s21.html#docbook-css01) 选择符,**body**标记中的内容如果没有专门指定,都应用花括号中定义的样式
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s21.html#docbook-css10) 花括号中的内容为样式定义
> [![3](https://box.kancloud.cn/2015-10-12_561bcb94ee26f.png)](ch27s21.html#docbook-css02) 字体
> [![4](https://box.kancloud.cn/2015-10-12_561bcb9508b82.png)](ch27s21.html#docbook-css03) 文字左对齐
> [![5](https://box.kancloud.cn/2015-10-12_561bcb95133e7.png)](ch27s21.html#docbook-css04) 背景色
> [![6](https://box.kancloud.cn/2016-01-06_568cdb4f32753.png)](ch27s21.html#docbook-css05) 文字色
> [![7](https://box.kancloud.cn/2016-01-06_568cdb4f41fcc.png)](ch27s21.html#docbook-css06) 页边距
> [![8](https://box.kancloud.cn/2016-01-06_568cdb4f5948a.png)](ch27s21.html#docbook-css07) 内部页边距
> [![9](https://box.kancloud.cn/2016-01-06_568cdb4f68749.png)](ch27s21.html#docbook-css08) 行高
> [![10](https://box.kancloud.cn/2016-01-06_568cdb4f83cf0.png)](ch27s21.html#docbook-css09) 行距
* **em**是相对尺寸,当前字体的尺寸=1em;**px**是绝对尺寸,像素,由显示器分辨率决定;
字体默认为 16px 大小,也就是说 1em=16px
看看我们生成的 Html 文件的源码
```
<div class="navheader">
<div class="navfooter">
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s21.html#docbook-css11) 给一个元素指定一个类
这里的页眉和页脚,使用的都是**div**标记,只不过类不同,怎么样为它们分别指定样式呢?在 CSS 文件中找到相关段落:
```
div`.`navheader {
border-bottom: 1px solid #dbddec;
}
div.navfooter {
border-top: 1px solid #dbddec;
}
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s21.html#docbook-css12) 类选择符,表示类为**navheader**的**div**标记,应用花括号中的样式
如果想对包含某一类的所有标记定义样式,可以单独使用类选择符
```
.command {
color: red;
}
```
* 不管**command**这个类出现在什么标记中,它都应用该样式
如果需要对多个不同的标记定义同一个样式,使用分组选择符
```
div.navheader`,` div.navfooter {
background: #ecedef;
margin: 0;
padding: 0.1em .5em;
}
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s21.html#docbook-css13) 分组选择符
空格为包含选择符
```
table tr td {
border:dashed #999;
text-align: left;
}
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s21.html#docbook-css14) 表示**table**标记中的**tr**标记中的**rd**标记
### 代码块的样式
我在 DocBook 中使用 **screen** 输出代码块,看看如何定义它的样式
```
.screen {
color: #000;
background-color: #e9e9e9;
font-weight: normal;
border: 1px dotted #666699;
max-height:20em;
overflow:auto;
}
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s21.html#docbook-css20) 定义边框粗细、类型、颜色。[[59](ch27s21.html#ftn.id3127683)]
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s21.html#docbook-css21) 定义最大高度
> [![3](https://box.kancloud.cn/2015-10-12_561bcb94ee26f.png)](ch27s21.html#docbook-css22) 代码块超出上面定义的最大高度时,加入一个滚动条
### 简单表格的样式
我用简单表格来放置一些需要排列整齐的文字
```
.informaltable table {
border:0;
border-top:dashed #999;
border-width:1px 1px 1px 1px;
margin-left: 10px;
margin-right: auto;
}
.informaltable table th, .informaltable table tr td {
border-right:0;
border-bottom:dashed #999;
border-width: 0 1px 1px 0;
padding: 0.2em 0.4em 0.2em 0.8em;
text-align: left;
}
```
> [![1](https://box.kancloud.cn/2015-10-12_561bcb76795ae.png)](ch27s21.html#docbook-css23) 包含选择符,类为`informaltable`的(div)标记,包含的`table`标记,应用下面的样式
> [![2](https://box.kancloud.cn/2015-10-12_561bcb768596e.png)](ch27s21.html#docbook-css24) **table**标记设定的边框为表格顶部和左边的边框,取消
> [![3](https://box.kancloud.cn/2015-10-12_561bcb94ee26f.png)](ch27s21.html#docbook-css25) 设定顶部的边框为点划线
> [![4](https://box.kancloud.cn/2015-10-12_561bcb9508b82.png)](ch27s21.html#docbook-css26) 分组选择符,分别选中表头和表体的单元格
> [![5](https://box.kancloud.cn/2015-10-12_561bcb95133e7.png)](ch27s21.html#docbook-css27) 表格底部和右边的边框由单元格设定[[60](ch27s21.html#ftn.id3127830)]
> [![6](https://box.kancloud.cn/2016-01-06_568cdb4f32753.png)](ch27s21.html#docbook-css28) 文字对齐
* * *
> [[58](ch27s21.html#id3127223)] 这个东西你不想要的时候满地都是,一旦你想找一个,可能还真找不到,没关系,可以用我的改。我也是改别人的:)
> [[59](ch27s21.html#id3127683)] 边框类型包括:solid实线、dashed点划线、dotted虚线、double双线、groove槽状、ridge脊状、inset凹陷、outset凸出
> [[60](ch27s21.html#id3127830)] 确实很别扭,但这不关 DocBook 的事,别忘了我们是通过 CSS 对 Html 进行定义
## 技巧
### 关于表格
在目录页中,会用每个表格的标题来生成表格清单。不希望被收录的可以使用 informaltable
可以通过在 CSS 中指定 table 和 informaltable 的样式来定义两种表格
### 交叉引用
可以放心的先引用,然后再定义被引用的部分。如果被引用的部分没有被定义,发布的时候 xsltproc 会给出提示
### calloutlist 自动编号问题
callout 如果不是定义在 screen、programlisting、synopsis 等块元素中,则下一个 calloutlist 中编号并不会重新开始,而是继续上次的。
经测试,callout 并不需要定义在 screen 等元素中,只要两个 calloutlist 中间有这些元素隔开就可以了。
可以定义一个不常用的元素,如 synopsis,来进行分隔。
只要在两个 calloutlist 之间的任何位置插入一个空标记 <synopsis/> 就可以了
当然了,生成的 Html 效果有一点怪异。在 CSS 中加入下面代码可以隐藏。
```
.synopsis {display:none;}
```
尽量把这个标记放在不影响显示的地方,例如两个 section 之间;这样即便意外的显示,也只显示在目录中
### 断行符
在 param.xsl 文件中加入
```
<xsl:template match="processing-instruction('linebreak')">
<br/>
</xsl:template>
```
在源文件中加入
```
<?linebreak?>
```
生成 Html 时替换为<br>
这里是演示
### 内部链接
内部链接时,要给结构元素定义 ID,而不要给 title 定义 ID,不然跳转时会到达错误的位置
- 开源世界旅行手册
- 授权
- 致谢
- 序言
- 更新纪录
- 导读
- 如何写作科技文档
- 部分 I. 气候
- 第 1 章 GUI? CLI?
- 第 2 章 UNIX 缩写风格
- 第 3 章 版本号的迷雾
- 第 4 章 Vim 还是 Emacs
- 第 5 章 DocBook 还是 TeX
- 第 6 章 完全用 Gnu/Linux 工作
- 第 7 章 病毒
- 第 8 章 磁盘 分区
- 第 9 章 文件系统
- 第 10 章 发行版介绍
- 第 11 章 编程语言
- 第 12 章 无根的根:无名师的 Unix 心传
- 部分 II. 地理
- 第 13 章 基础知识
- 第 14 章 命令系统
- 第 15 章 基本系统
- 第 16 章 软件管理
- 第 17 章 核心工具集
- 第 18 章 编译工具链
- 第 19 章 图形界面
- 第 20 章 国际化
- 第 21 章 内核
- 第 22 章 Grub
- 第 23 章 服务器
- 第 24 章 Vim 编辑器
- 第 25 章 Emacs 入门
- 第 26 章 正则表达式
- 第 27 章 docbook 指南
- 第 28 章 Git 版本控制系统
- 第 29 章 ConTeXt 入门指南
- 部分 III. 景观
- 第 30 章 终极 Shell -- ZSH
- 第 31 章 完美工作站 Archlinux
- 第 32 章 组织你的意念:Emacs org mode
- 第 33 章 Zsh+screen
- 第 34 章 gentoo stage3
- 第 35 章 硬件问题
- 第 36 章 网络设置
- 第 37 章 自制 LiveCD
- 第 38 章 awesome
- 第 39 章 openbox 工作环境
- 第 40 章 Emacs muse
- 第 41 章 写作工具链
- 第 42 章 使用 lftp
- 第 43 章 Firefox 使用技巧
- 第 44 章 FVWM
- 部分 IV. 地质
- 第 45 章 Unix
- 第 46 章 Gnu
- 第 47 章 软件业自由之神——Richard Stallman
- 第 48 章 Linux
- 第 49 章 GNOME与KDE的战争
- 第 50 章 Vim Emacs
- 第 51 章 年代纪
- 第 52 章 我的选择
- 第 53 章 补遗