使用 EPUB 制做数字图书

开始以前

本教程讲述如何建立 EPUB 格式的电子图书。EPUB 是一种基于 XML 的、对开发者友好的格式,正逐渐成为数字图书的事实标准。但 EPUB 不只可用于图书,还包括: php

  • 对文档打包以便离线阅读或者分发
  • 打包博客文章或者其余 Web 内容
  • 使用常见的开放源代码工具建立、搜索和整理

关于本教程

经常使用的缩写词

  • API:应用程序编程接口(application programming interface)
  • CSS:级联样式表(Cascading stylesheet)
  • DOM:文档对象模型(Document Object Model)
  • DTD:文档类型定义(Document type definition)
  • GUI:图形用户界面(Graphical user interface)
  • HTML:超文本标记语言(Hypertext Markup Language)
  • SAX:XML 简易 API(Simple API For XML)
  • W3C:万维网联盟(World Wide Web Consortium)
  • XHTML:可扩展的 HTML(Extensible HTML)
  • XML:可扩展标记语言

本教程首先手工建立一个 EPUB 图书,帮助您了解其构成和须要的文件。而后说明如何捆绑完成的数字图书,按照规范进行验证以及在不一样的阅读系统上测试。 css

而后讨论如何从 DocBook XML 生成 EPUB — 最经常使用的技术文档标准之一 — 以及如何使用 Python 实现从 DocBook 到 EPUB 的自动建立。 html

目标

经过本教程能够学习以下内容: java

  • 了解 EPUB 是什么,谁支持它,谁采用它
  • 了解 EPUB 包的结构,包括须要的文件及其模式
  • 如何从头建立一个内容简单而有效的 EPUB 文件
  • 使用开放源代码工具从 DocBook 生成 EPUB 文件,DocBook 是一种常见的技术文档和图书模式
  • 使用 Python 和 DocBook 自动转换成 EPUB

先决条件

本教程对操做系统没有特殊要求,可是应该熟悉建立文件和目录的机制。建议使用 XML 编辑器或者集成开发环境(IDE)。 git

对于本教程后半部分的 EPUB 建立自动化内容,须要读者了解基本的 XML 处理技巧 — XSLT、 DOM 或者基于 SAX 的解析 — 并熟悉使用 XML 原生 API 构造 XML 文档。 编程

阅读本教程不须要熟悉 EPUB 文件格式。 浏览器

系统需求

尝试本教程中的例子,须要一个 Java 解释器(1.5 或更高版本)和 Python 解释器(2.4 或更高版本)以及相应的 XML 库。不过,有经验的 XML 开发人员很容易将这些例子修改成适合任何编程语言和 XML 库。 网络

回页首 app

关于 EPUB 格式

了解 EPUB 的背景,EPUB 最适合作什么,以及 EPUB 和便携式文档格式(PDF)的区别。 jsp

什么是 EPUB?

EPUB 是可逆的数字图书和出版物 XML 格式,数字出版业商业和标准协会 International Digital Publishing Forum (IDPF) 制定的标准。IDPF 于 2007 年 10 月正式采用 EPUB,随后被主流出版商迅速采用。可使用各类开放源代码或者商业软件在全部主流操做系统、Sony PRS 之类的 e-ink 设备或者 Apple iPhone 之类的小型设备上阅读 EPUB 格式。

谁在使用 EPUB?只能用于图书吗?

虽然最先采用 EPUB 的是传统的印刷品出版商,可是这并不妨碍它在电子图书中的应用。利用免费的软件工具,能够将网页捆绑成 EPUB,转化成文本文件或者将原有的 DocBook XML 文档转化成结构良好的、有效的 EPUB(后一点将在 从 DocBook 到 EPUB 一节讨论)。

EPUB 与 PDF 有什么不一样?

PDF 仍然是世界上应用最普遍的电子文档格式。从图书出版商的角度来看,PDF 的优势包括:

  • PDF 文件容许对页面布局进行像素级的控制,包括复杂的打印格式,如多栏格式和奇偶页相间的格式。
  • 有多种不一样的 GUI 文档工具可生成 PDF,如 Microsoft® Office Word 和 Adobe® InDesign®。
  • PDF 阅读器很是普及,如今大多数计算机上都有安装。
  • PDF 能够嵌入特殊的字体,精确控制最终的输出结果。

三合一的标准

EPUB 包括三个单独的 IDPF 规范,虽然实际上将其统称为 EPUB 更保险:

  • Open eBook Publication Structure Container Format (OCF):定义了 EPUB 档案的目录树结构和文件结构(ZIP)。
  • Open Publication Structure (OPS):定义了电子图书的公共词汇表,特别是可做为图书内容的格式(好比 XHTML 和 CSS)。
  • Open Packaging Format (OPF):描述了 EPUB 必须的和可选的元数据、阅读顺序和目录。

此外,对于档案中的特定类型的内容,EPUB 还重用了其余一些标准,如 XHTML 1.0 和 Digital Accessible Information SYstem (DAISY)。

从软件开发人员的角度来看,PDF 还远远不够理想:

  • 这不是一种简单易学的标准,所以编写本身的 PDF 生成代码很是困难。
  • 虽然 PDF 如今是一种 International Organization for Standardization(ISO)标准(ISO 32000-1:2008),但过去一直受一家公司的控制:Adobe Systems。
  • 尽管多数编程语言都提供了 PDF 库,但不少是商业产品或者嵌入到 GUI 应用程序中,外部进程不容易控制。并不是全部的免费库都获得积极的维护。
  • PDF 原生文本能够经过程序提取出来并进行搜索,但不多能够对 PDF 进行标记以便简单可靠地转化成 Web 友好的格式。
  • PDF 文档不容易流动,就是说很难适应小屏幕或者对布局进行明显的改变。

为什么说 EPUB 对开发人员是友好的

EPUB 解决了 PDF 和开发人员友好性有关的全部瑕疵。一个 EPUB 就是一个简单 ZIP 格式文件(使用 .epub 扩展名),其中包括按照预先定义的方式排列的文件。如何制做 ZIP 文档有一些技巧,稍后将在 将 EPUB 文件捆绑为 ZIP 文档 一节介绍。除此之外,EPUB 很是简单:

  • EPUB 中的全部内容基本上都是 XML。EPUB 文件可以使用标准 XML 工具建立,不须要任何专门或者私有的软件。
  • EPUB 内容(eBook 的具体内容)基本上都是 XHTML 1.1(另外一种格式是 DTBook,为视力受限者编码书籍的一种标准。关于 DTBook 的更多信息请参阅 参考资料,本教程中不涉及这部分)。
  • 大多数 EPUB XML 模式都来自现成的、可免费得到的、已发布的规范。

最关键的在于 EPUB 元数据是 XMLEPUB 内容是 XHTML。若是您的文档构建系统产生的结果用于 Web 和/或基于 XML,那么也可用于生成 EPUB。

回页首

建立第一个 EPUB

最小的 EPUB 包至少要包含几个文件。规范对于 EPUB 包中这些文件的格式、内容和位置要求可能很严格。这一节讨论使用 EPUB 标准必须了解的基础知识。

解剖 EPUB 包

小型 EPUB 文件的基本结构遵循 清单 1 所示的样式。准备好分发以前,整个目录结构被压缩到一个 ZIP 格式文件中,几点特殊要求将在 用 ZIP 打包 EPUB 文件 一节讨论。

清单 1. 简单 EPUB 档案的目录和文件结构
mimetype
META-INF/
   container.xml
OEBPS/
  content.opf
  title.html
  content.html
  stylesheet.css
  toc.ncx
  images/
     cover.png

提示:可 下载 符合该结构的一个电子图书,但建议按照本教程的说明本身建立一个。

编写 EPUB 图书以前首先建立 EPUB 项目的目录。打开文本编辑器或者 Eclipse 之类的 IDE。建议采用支持 XML 的编辑器 — 具体而言就是可以根据 参考资料 给出的 Relax NG 模式进行验证。

mimetype 文件

这个文件很是简单,必须命名为 mimetype,文件内容以下:

application/epub+zip

要注意,mimetype 文件不能包含新行或者回车。

此外,mimetype 文件必须做为 ZIP 档案中的第一个文件,并且自身不能压缩。用 ZIP 打包 EPUB 文件 一节将介绍如何使用通常的 ZIP 参数将其包含进来。如今建立该文件并保存,并确保它在 EPUB 项目的根目录中。

META-INF/container.xml

EPUB 根目录下必须包含 META-INF 目录,并且其中要有一个文件 container.xml。EPUB 阅读系统首先查看该文件,它指向数字图书元数据的位置。

建立目录 META-INF。在其中建立一个新文件 container.xml。container 文件很是小,可是对结构要求很严格。将 清单 2 中的代码粘贴到 META-INF/container.xml 中。

清单 2. container.xml 文件
<?xml version="1.0"?>
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
  <rootfiles>
    <rootfile full-path="OEBPS/content.opf"
     media-type="application/oebps-package+xml" />
  </rootfiles>
</container>

full-path(粗体)的值仅仅是该文件的一部分,不一样的文件可能相差甚大。目录路径必须相对于 EPUB 文件根目录自己,而不是 META-INF 目录。

关于 META-INF

META-INF 目录还能够包含其余几个文件。这些文件使 EPUB 支持数字签名、加密和数字版权管理(DRM)。本教程不讨论这些主题。更多信息请参阅 OCF 规范。

mimetype 和 container 是 EPUB 档案中仅有的两个须要严格限制位置的文件。建议(尽管不是必须的)将其余文件保存到 EPUB 的子目录下(按照惯例,一般被称为 OEBPS,即 Open eBook Publication Structure,但不是必须的)。

接下来在 EPUB 项目中建立目录 OEBPS。本教程下一节将介绍 OEBPS 中的文件 — 数字图书的核心:元数据和页面。

打开 Packaging Format 元数据文件

尽管该文件名没有特殊要求,但一般被称为 content.opf。它指定了图书中全部 内容的位置,如文本和图像等其余媒体。它还给出了另外一个元数据文件,内容的 Navigation Center eXtended (NCX) 表。

该 OPF 文件是 EPUB 规范中最复杂的元数据。建立 OEBPS/content.opf 并粘贴 清单 3 所示的内容。

清单 3. 包含示例元数据的 OPF content 文件
<?xml version='1.0' encoding='utf-8'?>
<package xmlns="http://www.idpf.org/2007/opf" 
            xmlns:dc="http://purl.org/dc/elements/1.1/" 
            unique-identifier="bookid" version="2.0">
  <metadata>
    <dc:title>Hello World: My First EPUB</dc:title>
    <dc:creator>My Name</dc:creator>
    <dc:identifier id="bookid">urn:uuid:12345</dc:identifier>
    <meta name="cover" content="cover-image" />
  </metadata>
  <manifest>
    <item id="ncx" href="toc.ncx" media-type="text/xml"/>
    <item id="cover" href="title.html" media-type="application/xhtml+xml"/>
    <item id="content" href="content.html" media-type="application/xhtml+xml"/>
    <item id="cover-image" href="images/cover.png" media-type="image/png"/>
    <item id="css" href="stylesheet.css" media-type="text/css"/>
  </manifest>
  <spine toc="ncx">
    <itemref idref="cover" linear="no"/>
    <itemref idref="content"/>
  </spine>
  <guide>
    <reference href="cover.html" type="cover" title="Cover"/>
  </guide>
</package>

OPF 模式与名称空间

OPF 文档自己必须使用名称空间 http://www.idpf.org/2007/opf,元数据则使用 Dublin Core Metadata Initiative (DCMI) 名称空间http://purl.org/dc/elements/1.1/

最好如今将 OPF 和 DCMI 模式添加到 XML 编辑器中。EPUB 用到的全部模式均可以 下载

元数据

Dublin Core 定义了一组经常使用的元数据,可用于描述各类不一样的数字资料,它不是 EPUB 规范的一部分。全部这些术语均可以出如今 OPF 元数据部分。编写要分发的 EPUB 时,这里能够放不少内容,目前来讲 清单 4 的内容就足够了。

清单 4. OPF 元数据摘要
...
<metadata>
  <dc:title>Hello World: My First EPUB</dc:title>
  <dc:creator>My Name</dc:creator>
  <dc:identifier id="bookid">urn:uuid:12345</dc:identifier>
  <meta name="cover" content="cover-image" />
</metadata>
...

有两个术语是必须的,即 title 和 identifier。按照 EPUB 规范,标识符必须 是唯一的,可是这个唯一的值要靠数字图书的建立者来定义。对于图书出版商来讲,这个字段通常包含 ISBN 或者 Library of Congress 编号。对于其余 EPUB 建立者,能够考虑使用 URL 或者很大的随机生成的唯一用户 ID(UUID)。要注意,属性 unique-identifier 的值必须和 dc:identifier 元素的 ID 属性匹配。

其余和内容相关的能够考虑添加的元数据包括:

  • 语言(如 dc:language)。
  • 出版日期(如 dc:date)。
  • 出版商(如 dc:publisher)。(能够是公司或我的的名称)。
  • 版权信息(如 dc:rights)。(若是采用 Creative Commons 许可证,能够将许可证的 URL 放在这里)。

关于 DCMI 的更多信息请参阅 参考资料

EPUB 规范没有要求包含 name 属性值为 cover 的 meta 元素,但为了增长封面和图像的可移植性,建议这样作。一些 EPUB 呈现程序喜欢使用图像文件做为封面,另外一些则愿意使用包含内联封面图像的 XHTML 文件。该例子显示了这两种状况。meta 元素的 content 属性的值应该是图书封面图像在 manifest 中的 ID 号,manifest 是 OPF 文件的一部分。

Manifest

OPF manifest 列出了 EPUB 内容(不包括元数据)中的全部资源。就是说,一般是组成电子图书文本的一组 XHTML 文件再加上一些相关的媒体如图像。EPUB 鼓励使用 CSS 设定图书内容的样式,所以 manifest 中也包含 CSS。进入数字图书的全部文件都必须在 manifest 中列出。

清单 5 显示了 manifest 的一部分。

清单 5. OPF manifest 的一部分
...
<manifest>
  <item id="ncx" href="toc.ncx" media-type="text/xml"/>
  <item id="cover" href="title.html" media-type="application/xhtml+xml"/>
  <item id="content" href="content.html" media-type="application/xhtml+xml"/>
  <item id="cover-image" href="images/cover.png" media-type="image/png"/>
  <item id="css" href="stylesheet.css" media-type="text/css"/>
</manifest>
...

高级 OPF manifest

更高级的 manifest 文件可能包含多个 XHTML 文件以及图像和 CSS。可 下载 一个完整的包含各类常见类型的 EPUB 例子。

第一项 toc.ncx(参见 下一节)是必须的。全部的项都有相应的 media-type 值,XHTML 内容的媒体类型为 application/xhtml+xml。媒体类型必须正确,不能 是 text/html或者其余类型。

EPUB 支持四种核心 图像文件类型:Joint Photographic Experts Group (JPEG)、Portable Network Graphics (PNG)、Graphics Interchange Format (GIF) 和 Scalable Vector Graphics (SVG)。若是可以提供对核心类型的后退转换(fall-back),也可包含不支持的文件类型。关于后退转换内容的更多信息请参阅 OPF 规范。

href 属性的值应该是一个相对于该 OPF 文件 的统一资源标识符(URI)。(很容易和 container.xml 中对 OPF 文件的引用混淆,其中的引用是相对于 EPUB 的总体引用)。这里的 OPF 文件位于和内容相同的 OEBPS 目录中,所以不须要路径信息。

Spine

manifest 告诉 EPUB 阅读器哪些文件属于档案,spine 则指定这些文件出现的顺序或 — 按照 EPUB 的说法 — 数字图书的线性阅读顺序。能够将 OPF spine 看做是书中 “页面” 的顺序。按照文档顺序从上到下依次读取 spine。清单 6 显示了 OPF 文件的一个片断。

清单 6. OPF spine 的一部分
...
<spine toc="ncx">
  <itemref idref="cover" linear="no"/>
  <itemref idref="content"/>
</spine>
...

每一个 itemref 元素都须要有一个 idref 属性,而且和 manifest 中的某个 ID 匹配。toc 属性也是必需的。它引用 manifest 中表示内容 NCX 表文件名的 ID。

spine 中的 linear 属性代表该项是做为线性阅读顺序中的一项,仍是和前后次序无关。建议将封面定义为 linear=no。符合 EPUB 规范的阅读系统将首先打开 spine 中没有 设置为 linear=no 中的第一项。

Guide

OPF 内容文件的最后一部分是 guide。这一节是可选的,但最好保留。清单 7 显示了 guide 文件的部份内容。

清单 7. OPF guide 的一部分
...
<guide>
  <reference href="cover.html" type="cover" title="Cover"/>
</guide>
...

guide 能够为 EPUB 阅读系统提供语义信息。manifest 定义了 EPUB 中的物理资源,spine 提供了这些资源的顺序信息,guide 负责解释这些部分的含义。下面是能够出如今 OPF guide 中的部分值:

  • cover: 图书封面
  • title-page: 包含做者和出版商信息的页面
  • toc:目录

完整的列表请参阅 OPF 2.0 规范(参见 参考资料)。

内容的 NCX 表

NCX 和 OPF 元数据的交叉

因为 NCX 源自其余标准,使用 NCX 编码的信息和 OPF 内容之间存在重复。若是经过程序生成 EPUB,这算不上什么问题,由于一样的代码可输出到两个文件中。两个位置的信息要一致,不一样的 EPUB 读者可能使用不一样位置的值。

尽管 OCF 文件是做为 EPUB 自己的一部分定义的,但最后一个主要的元数据文件参照了不一样的数字图书标准。DAISY 是一个专门为不能使用传统书籍的读者设计数据格式的组织,一般是由于视力受损或者不便于使用印刷的书籍。EPUB 借用了 DAISY 的 NCX DTD。NCX 定义了数字图书的目录表。复杂的图书中,目录表一般采用层次结构,包括嵌套的内容、章和节。

使用 XML 编辑器建立 OEBPS/toc.ncx 并粘贴 清单 8 所示的代码。

清单 8. 简单的 NCX 文件
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE ncx PUBLIC "-//NISO//DTD ncx 2005-1//EN" 
                 "http://www.daisy.org/z3986/2005/ncx-2005-1.dtd">
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
  <head>
    <meta name="dtb:uid" content="urn:uuid:12345"/>
    <meta name="dtb:depth" content="1"/>
    <meta name="dtb:totalPageCount" content="0"/>
    <meta name="dtb:maxPageNumber" content="0"/>
  </head>
  <docTitle>
    <text>Hello World: My First EPUB</text>
  </docTitle>
  <navMap>
    <navPoint id="navpoint-1" playOrder="1">
      <navLabel>
        <text>Book cover</text>
      </navLabel>
      <content src="title.html"/>
    </navPoint>
    <navPoint id="navpoint-2" playOrder="2">
      <navLabel>
        <text>Contents</text>
      </navLabel>
      <content src="content.html"/>
    </navPoint>
  </navMap>
</ncx>

NCX 元数据

DTD 要求 NCX <head> 标记中包含四个 meta 元素:

  • uid: 数字图书的唯一 ID。该元素应该和 OPF 文件中的 dc:identifier 对应。
  • depth:反映目录表中层次的深度。该例只有一层,所以是 1
  • totalPageCount 和 maxPageNumber:仅用于纸质图书,保留 0 便可。

docTitle/text 的内容是图书的标题,和 OPF 中的 dc:title 匹配。

NCX navMap

NCX 和 OPF spine 有什么不一样?

二者很容易混淆,由于两个文件都描述了文档的顺序和内容。要说明二者的区别,最简单的办法就是拿印刷书来打比方:OPF spine 描述了书中的各个章节是如何实际链接起来的,比方说翻过第一章的最后一页就看到第二章的第一页。NCX 在图书的一开始描述了目录。目录确定会包含书中主要的章节,可是还可能包含没有单独分页的小节。

一条法则是 NCX 包含的 navPoint 元素一般比 OPF spine 中的 itemref 元素多。实际上,spine 中的全部项都会出如今 NCX 中,但 NCX 可能更详细。

navMap 是 NCX 文件中最重要的部分,定义了图书的目录。navMap 包含一个或多个navPoint 元素。每一个 navPoint 都要包含下列元素:

  • playOrder 属性,说明文档的阅读顺序。和 OPF spine 中 itemref 元素的顺序相同。
  • navLabel/text 元素,给出该章节的标题。一般是章的标题或者数字,如 “第一章”,或者 — 像这个例子同样 — “封面”。
  • content 元素,它的 src 属性指向包含这些内容的物理资源。就是 OPF manifest 中声明的文件(也可以使用片断标识符引用 XHTML 内容中的锚元素 — 好比content.html#footnote1)。
  • 还能够有一个或多个 navPoint 元素。NCX 使用嵌套的导航点表示层次结构的文档。

该文档的结构很是简单:只有两页,不存在嵌套关系。就是说有两个 navPoint 元素,它们的 playOrder 值按升序排列,从 1 开始。在 NCX 中能够命名这些章节,以便读者跳到电子图书不一样的部分。

添加最后的内容

如今知道了 EPUB 须要的全部元数据,能够加入真正的图书内容了。可使用 下载 的内容,也能够本身写,只要文件名和元数据匹配便可。

而后建立下列文件和文件夹:

  • title.html:图书的标题页。建立该文件并在其中包含引用封面图片的 img 元素,src 的属性值为 images/cover.png。
  • images:在 OEBPS 下建立该文件夹,而后复制给定的示例图片(或者建立本身的图片)并命名为 cover.png
  • content.html:图书的实际文字内容。
  • stylesheet.css:将该文件放在和 XHTML 文件相同的 OEBPS 目录中。该文件能够包含任意 CSS 声明,好比设置字体或者文字颜色。清单 10 给出了一个 CSS 文件的例子。

EPUB 图书中的 XHTML 和 CSS

清单 9 包含了一个有效的 EPUB 内容页。将其做为标题页(title.html),用一个相似的页面做为主要内容页(content.html)。

清单 9. 示例 title 页面(title.html)
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Hello World: My First EPUB</title>
    <link type="text/css" rel="stylesheet" href="stylesheet.css" />
  </head>
  <body>
    <h1>Hello World: My First EPUB</h1>
    <div><img src="images/cover.png" alt="Title page"/></div>
  </body>
</html>

EPUB 的 XHTML 须要符合几条要求,和通常的 Web 开发不一样:

  • 内容必须是有效的 XHTML 1.1:XHTML 1.0 Strict 和 XHTML 1.1 的主要区别是去掉了 name 属性(使用 ID 引用锚元素)。
  • img 元素只能引用电子图书的本地图片:该元素不能引用 Web 上的图片。
  • 避免使用 script:EPUB 阅读器不必定支持 JavaScript 代码。

EPUB 支持 CSS 的方式有一些细微的差异,可是不会影响样式表的通常用法(详情参阅 OPS 规范)。清单 10 中的简单 CSS 文件能够设置基本的字体,并把标题设为红色。

清单 10. 电子图书的示例样式表(stylesheet.css)
body {
  font-family: sans-serif;     
}
h1,h2,h3,h4 {
  font-family: serif;     
  color: red;
}

有趣的是,EPUB 很是支持 CSS 2 @font-face 规则,容许内嵌字体。若是建立技术文档,这点可能可有可无,可是若是用多种语言或针对特定领域编写 EPUB,可以指定具体的字体数据就颇有必要了。

如今已经准备好了建立 EPUB 图书所需的全部内容。下一节将按照 OCF 规范将图书装订起来,并看看如何进行验证。

回页首

打包和检查 EPUB

如今,应当能够对 EPUB 包进行打包。这个包能够是您本身建立的一本新书,也可以使用从本文 下载 部分得到的原始文件。

用 ZIP 打包 EPUB 文件

EPUB 规范的 OEBPS Container Format 讨论了 EPUB 和 ZIP,最重要的几点是:

  • 档案中的第一个文件必须是 mimetype 文件(参见本教程 Mimetype 一节)。mimetype 文件不能被压缩。这样非 ZIP 工具就能从 EPUB 包的第 30 个字节开始读取原始字节,从而发现 mimetype。
  • ZIP 档案不能加密。EPUB 支持加密,但不是在 ZIP 文件这一层上。

在类 UNIX® 操做系统上,使用 ZIP 2.3 可经过两个命令来建立 EPUB ZIP 文件,如 清单 11 所示(这些命令假设当前工做目录为 EPUB 项目。)

清单 11. 将 EPUB 打包成有效的 epub+zip 文件
$ zip -0Xq  my-book.epub mimetype
$ zip -Xr9Dq my-book.epub *

第一个命令建立了一个新的 ZIP 档案,并添加了没有进行压缩的 mimetype 文件。第二个命令添加其余内容。选项 -X 和 -D 最大限度地减小 .zip 文件中可有可无的信息;-r 递归地包含 META-INF 和 OEBPS 目录的内容。

EPUB 验证

虽然 EPUB 标准并不很难,但其 XML 文件必须符合特定的模式。若是使用模式感知的 XML 编辑器生成元数据和 XHTML,就能事半功倍。对 EpubCheck 包进行最后检查(参见 参考资料)。

Adobe 负责维护 EpubCheck 包,它是采用 Berkeley Software Distribution (BSD) 许可证的开源项目。它是一个能够做为独立工具、Web 应用程序运行的 Java 程序,或者能够将它集成到在 Java Runtime Environment (JRE) 1.5 或更高版本下运行的应用程序中。

在命令行中运行很是简单。清单 12 给出了一个例子。

清单 12. 运行 EpubCheck 工具程序
$ java -jar /path/to/epubcheck.jar my-book.epub

若是没有建立辅助文件或者元数据文件出错,可能会看到 清单 13 所示的错误消息。

清单 13. EpubCheck 错误
my-book.epub: image file OEBPS/images/cover.png is missing
my-book.epub: resource OEBPS/stylesheet.css is missing
my-book.epub/OEBPS/title.html(7): 'OEBPS/images/cover.png': 
     referenced resource missing in the package

Check finished with warnings or errors!

这时候可能须要设置 CLASSPATH 使它指向 EpubCheck 的安装位置,由于确实须要导入几个外部库。若是获得这样的消息则须要设置 CLASSPATH:

org.xml.sax.SAXParseException: no implementation available for schema language 
   with namespace URI "http://www.ascc.net/xml/schematron"

若是验证成功,就会看到 “No errors or warnings detected(没有检测到错误或警告)”。祝贺您完成了第一个 EPUB!

查看 EPUB

测试不只仅是验证,还要保证书的外观看起来不错。样式表能正确工做吗?章节的逻辑顺序是否正确?书中是否包含了全部须要的内容?

有多重 EPUB 阅读器可供选择。图 1 显示了 Adobe Digital Editions (ADE) 的屏幕截图,这是最经常使用的 EPUB 阅读器。

图 1. ADE 中显示的 EPUB
ADE 中显示的 EPUB

字体颜色和图像都显示出来了,不错。ADE 未能用 sans-serif 字体正确地显示标题,不过这多是 CSS 的问题。这时候最好换一个阅读器试试。图 2 是用我本身编写的、开放源代码的、基于 Web 的 EPUB 阅读器 Bookworm 显示的同一本书。

图 2. 在 Bookworm 中显示 EPUB
在 Bookworm 中显示 EPUB

这里的问题在于 ADE 不支持这种特殊声明。若是数字图书的格式很是重要,那么就必须了解不一样阅读软件的特色。

前面咱们费了很大力气手工建立了一个简单的 EPUB,如今看看如何将一种常见的 XML 文档 DocBook 转换成 EPUB。

回页首

从 DocBook 到 EPUB

DocBook 是须要维护大型技术文档的开发人员经常使用的选择。与传统字处理程序生成的文件不一样,可使用基于文本的版本控制系统管理 DocBook 输出。因为 DocBook 是 XML,很容易将其转换成不一样输出格式。2008 年夏天出现了正式的 DocBook XSL 项目,将 EPUB 做为一种输出格式。

使用 XSLT 运行 DocBook-to-EPUB 管道

从一个简单 DocBook 文档开始,如 清单 14 所示。 该文档的类型为 book,包括前言、两个章节以及标题页面中内联显示的图像。图像和 DocBook 源文件的目录相同。能够本身建立该文件和标题页,也可 下载 本文提供的例子。

清单 14. 简单的 DocBook 图书
<?xml version="1.0" encoding="utf-8"?`>  
<book>
  <bookinfo>
    <title>My EPUB book</title>
    <author><firstname>Liza</firstname>
            <surname>Daly</surname></author>
    <volumenum>1234</volumenum>
  </bookinfo>
  <preface id="preface">  
    <title>Title page</title>
    <figure id="cover-image">
      <title>Our EPUB cover image icon</title>
      <graphic fileref="cover.png"/>
    </figure>
  </preface>
  <chapter id="chapter1"> 
    <title>This is a pretty simple DocBook example</title>
    <para>
      Not much to see here. 
    </para>
  </chapter>
  <chapter id="end-notes"> 
    <title>End notes</title>
    <para>
      This space intentionally left blank.
    </para>
  </chapter>
</book>

而后从 参考资料 下载最新版本的 DocBook XSL 样式表,并安装 xsltproc 或 Saxon 之类的 XSLT 处理程序。本文使用 xsltproc,大多数类 UNIX 系统上都能找到。转换 DocBook 文件,只须要用 DocBook XSL 中包含的 EPUB 模块运行该文件便可,如 清单 15 所示。

清单 15. 将 DocBook 转化成 EPUB
$ xsltproc /path/to/docbook-xsl-1.74.0/epub/docbook.xsl docbook.xml
Writing OEBPS/bk01-toc.html for book
Writing OEBPS/pr01.html for preface(preface)
Writing OEBPS/ch01.html for chapter(chapter1)
Writing OEBPS/ch02.html for chapter(end-notes)
Writing OEBPS/index.html for book
Writing OEBPS/toc.ncx
Writing OEBPS/content.opf
Writing META-INF/container.xml

定制 DocBook XSL

DocBook-to-EPUB 转换管道仍然比较新,可能须要定制 XSLT 以获得须要的结果。

而后添加 mimetype 文件并创建 epub+zip 档案。清单 16 显示了这三个命令和经过 EpubCheck 验证程序的结果。

清单 16. 从 DocBook 建立 EPUB 档案
$ echo "application/epub+zip" > mimetype
$ zip -0Xq  my-book.epub mimetype
$ zip -Xr9D my-book.epub *
$ java -jar epubcheck.jar my-book.epub 
No errors or warnings detected

太简单了!图 3 显示了 ADE 中的结果。

图 3. ADE 显示了从 DocBook 转化获得的 EPUB
ADE 显示了从 DocBook 转化获得的 EPUB

利用 Python 和 lxml 实现 DocBook-to-EPUB 转换自动化

DocBook XSL 大大下降了生成 EPUB 的复杂性,可是在 XSLT 以外还有几个步骤要执行。最后一节给出的 Python 示例程序可以生成有效的 EPUB 包。本教程显示了不一样的方法,可 下载 完整的 docbook2epub.py 程序。

可以使用不一样的 Python XSLT 库,我喜欢 lxml。它不但提供了 XSLT 1.0 必要的功能,并且解析效率高,彻底支持 XPath 1.0,提供了专门处理 HTML 的扩展。若是喜欢不一样的库或者使用 Python 之外的编程语言,修改这些例子也很简单。

用 lxml 调用 DocBook XSL

使用 lxml 调用 XSLT 的最有效办法是事先解析 XSLT,而后建立反复使用的转换器。这样很方便,由于个人 DocBook-to-EPUB 须要转换多个 DocBook 文件。如 清单 17 所示。

清单 17. 使用 lxml 运行 DocBook XSL
import os.path
from lxml import etree

def convert_docbook(docbook_file):
    docbook_xsl = os.path.abspath('docbook-xsl/epub/docbook.xsl')
    # Give the XSLT processor the ability to create new directories
    xslt_ac = etree.XSLTAccessControl(read_file=True, 
                                      write_file=True, 
                                      create_dir=True, 
                                      read_network=True, 
                                      write_network=False)
    transform = etree.XSLT(etree.parse(docbook_xsl), access_control=xslt_ac)
    transform(etree.parse(docbook_file))

DocBook XSL 中的 EPUB 模块建立输出文件自己,所以转换过程什么也不返回。相反,DocBook 在当前工做目录中建立了两个文件夹(META-INF 和 OEBPS),包含转换的结果。

将图片和其余资源复制到档案中

DocBook XSL 不会对文档中使用的任何图片执行操做,仅仅建立元数据文件和要呈现的 XHTML。因为 EPUB 规范要求 content.opf manifest 列出全部资源,能够预料到 manifest 将寻找原始 DocBook 文件引用的任何图片。清单 18 显示了这种技术,其中假定 path 变量包含 DocBook XSLT 生成的、当前所处理的 EPUB 的路径。

清单 18. 解析 OPF 内容文件以寻找缺失的资源
import os.path, shutil
from lxml import etree

def find_resources(path='/path/to/our/epub/directory'):
    opf = etree.parse(os.path.join(path, 'OEBPS', 'content.opf'))

    # All the opf:item elements are resources
    for item in opf.xpath('//opf:item', 
                          namespaces= { 'opf': 'http://www.idpf.org/2007/opf' }):

        # If the resource was not already created by DocBook XSL itself, 
        # copy it into the OEBPS folder
        href = item.attrib['href']
        referenced_file = os.path.join(path, 'OEBPS', href):
        if not os.path.exists(referenced_file):
            shutil.copy(href, os.path.join(path, 'OEBPS'))

自动建立 mimetype

DocBook XSL 不会建立 mimetype 文件,不过 清单 19 中所示的代码能够完成这项任务。

清单 19. 建立 mimetype 文件
def create_mimetype(path='/path/to/our/epub/directory'):
    f = '%s/%s' % (path, 'mimetype')
    f = open(f, 'w')
    # Be careful not to add a newline here
    f.write('application/epub+zip')
    f.close()

用 Python 建立 EPUB 包

如今只须要将文件打包成有效的 EPUB ZIP 包。须要分两步:将未经压缩的 mimetype 文件做为第一个文件加进去,而后添加其余目录。如 清单 20 所示。

清单 20. 使用 Python zipfile 模块建立 EPUB 包
import zipfile, os

def create_archive(path='/path/to/our/epub/directory'):
    '''Create the ZIP archive.  The mimetype must be the first file in the archive 
    and it must not be compressed.'''

    epub_name = '%s.epub' % os.path.basename(path)

    # The EPUB must contain the META-INF and mimetype files at the root, so 
    # we'll create the archive in the working directory first and move it later
    os.chdir(path)    

    # Open a new zipfile for writing
    epub = zipfile.ZipFile(epub_name, 'w')

    # Add the mimetype file first and set it to be uncompressed
    epub.write(MIMETYPE, compress_type=zipfile.ZIP_STORED)
    
    # For the remaining paths in the EPUB, add all of their files
    # using normal ZIP compression
    for p in os.listdir('.'):
        for f in os.listdir(p):
            epub.write(os.path.join(p, f)), compress_type=zipfile.ZIP_DEFLATED)
    epub.close()

好了!切记要进行验证。

回页首

结束语

上一节 中的 Python 脚本仅仅是充分实现 EPUB 转换自动化的第一步。为了简化起见,没有涉及一些常见的状况,好比任意嵌套的路径、样式表或者内嵌字体。Ruby 爱好者能够看看 DocBook XSL 分发包中所含的 dbtoepub,方法与此相似。

由于 EPUB 仍是一种比较年轻的格式,不少有效的转换方法还等待人们去创造。所幸的是,多数结构化标记,如 reStructuredText 或 Markdown 都已经存在生成 HTML 或者 XHTML 的渠道了;稍加修改来生成 EPUB 应该很是容易,尤为是有了本文所示的 DocBook-to-EPUB Python 或 Ruby 脚本这些例子之后。

由于 EPUB 基本上就是 ZIP 和 XHTML,与其使用 .zip 文件,没有理由不使用 EPUB 来分发文档。拥有 EPUB 阅读器的读者可从传统元数据和自动目录表收益,没有阅读器的读者也可将其做为通常 ZIP 文件并在浏览器中查看 XHTML 内容。考虑将 EPUB 生成的代码添加到各种文档系统中,如 Javadoc 或 Perldoc。EPUB 是为具备图书长度的文档设计的,所以很是适合愈来愈多的在线或者渐进式编程图书。

回页首

下载

描述 名字 大小
本教程中用于构建 EPUB 的资源 epub-raw-files.zip 8KB
EPUB 工具的 DocBook1 docbook-to-epub.zip 7KB

注意:

  1. 该 .zip 文件包含教程中的 DocBook XML 示例文件和完整的 docbook2epub.py 脚本。lxml 和 DocBook XSL 必须单独下载,相关连接参见 参考资料

参考资料

学习

得到产品和技术

  • EpubCheck:Adobe EpubCheck 是建立 EPUB 的很是棒的工具。下载后可做为独立应用程序、Web 应用程序或库(须要 Java 1.5 或更高版本)运行。
  • DocBook XSL:下载将 DocBook 转化为 EPUB 的样式表的最新版本。这个 DocBook XSL 包还包括生成完整 EPUB 档案的 Ruby 脚本,与本教程所述 Python 脚本相似。
  • lxml:若是没有安装的话请安装 lxml,它是功能最齐全的 Python XML 库。关于 lxml 的更多信息请参阅做者的另外一篇文章 使用用 Python 编写的 lxml 实现高性能 XML 解析(Liza Daly,developerWorks,2008 年 10 月)。
  • Adobe Digital Editions 和 Bookworm:为了测试 EPUB,最接近规范的电子图书阅读器是 ADE,这是一个跨平台的桌面应用程序;还有做者编写的基于 Web 的电子图书阅读器 Bookwork,它使用了 EPUB 呈现所用的浏览器。
  • IBM 试用软件:使用这些试用软件开发您的下一个项目,可直接从 developerWorks 下载,包括 DB2®、Lotus®, Rational®、Tivoli® 和 WebSphere® 提供的应用程序开发工具和中间件产品。

讨论

相关文章
相关标签/搜索