程序员制作epub电子书

来自:http://www.cnblogs.com/linlf03/archive/2011/12/15/2285953.html

/////////////////////////////////////////////////////////////////////////////////////////////Page1

简介:是否需要分发文档、创建电子图书或者把喜欢的博客文章存档?EPUB是一种开放式的数字图书规范,以常用的技术如XML、CSS和XHTML为基础,EPUB文件可在便携式的e-ink设备、移动电话和桌面计算机上阅读。本教程详细阐述了EPUB格式,首先用Java?技术示范了EPUB验证,然后详细说明如何使用DocBook和Python自动创建EPUB。

开始之前

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

•对文档打包以便离线阅读或者分发

•打包博客文章或者其他Web内容

•使用常见的开放源代码工具创建、搜索和整理

关于本教程

常用的缩写词

•API:应用程序编程接口(applicationprogramminginterface)

•CSS:级联样式表(Cascadingstylesheet)

•DOM:文档对象模型(DocumentObjectModel)

•DTD:文档类型定义(Documenttypedefinition)

•GUI:图形用户界面(Graphicaluserinterface)

•HTML:超文本标记语言(HypertextMarkupLanguage)

•SAX:XML简易API(SimpleAPIForXML)

•W3C:万维网联盟(WorldWideWebConsortium)

•XHTML:可扩展的HTML(ExtensibleHTML)

•XML:可扩展标记语言

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

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

目标

通过本教程可以学习如下内容:

•了解EPUB是什么,谁支持它,谁采用它

•了解EPUB包的结构,包括需要的文件及其模式

•如何从头创建一个内容简单而有效的EPUB文件

•使用开放源代码工具从DocBook生成EPUB文件,DocBook是一种常见的技术文档和图书模式

•使用Python和DocBook自动转换成EPUB

先决条件

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

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

阅读本教程不需要熟悉EPUB文件格式。

系统需求

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

/////////////////////////////////////////////////////////////////////////////////////////////Page2

关于EPUB格式

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

什么是EPUB?

EPUB是可逆的数字图书和出版物XML格式,数字出版业商业和标准协会InternationalDigitalPublishingForum(IDPF)制定的标准。IDPF于2007年10月正式采用EPUB,随后被主流出版商迅速采用。可以使用各种开放源代码或者商业软件在所有主流操作系统、SonyPRS之类的e-ink设备或者AppleiPhone之类的小型设备上阅读EPUB格式。

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

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

EPUB与PDF有什么不同?

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

•PDF文件允许对页面布局进行像素级的控制,包括复杂的打印格式,如多栏格式和奇偶页相间的格式。

•有多种不同的GUI文档工具可生成PDF,如Microsoft?OfficeWord和Adobe?InDesign?。

•PDF阅读器非常普及,现在大多数计算机上都有安装。

•PDF可以嵌入特殊的字体,精确控制最终的输出结果。

三合一的标准

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

•OpeneBookPublicationStructureContainerFormat(OCF):定义了EPUB档案的目录树结构和文件结构(ZIP)。

•OpenPublicationStructure(OPS):定义了电子图书的公共词汇表,特别是可作为图书内容的格式(比如XHTML和CSS)。

•OpenPackagingFormat(OPF):描述了EPUB必须的和可选的元数据、阅读顺序和目录。

此外,对于档案中的特定类型的内容,EPUB还重用了其他一些标准,如XHTML1.0和DigitalAccessibleInformationSYstem(DAISY)。

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

•这不是一种简单易学的标准,因此编写自己的PDF生成代码非常困难。

•虽然PDF现在是一种InternationalOrganizationforStandardization(ISO)标准(ISO32000-1:2008),但过去一直受一家公司的控制:AdobeSystems。

•尽管多数编程语言都提供了PDF库,但很多是商业产品或者嵌入到GUI应用程序中,外部进程不容易控制。并非所有的免费库都得到积极的维护。

•PDF原生文本可以通过程序提取出来并进行搜索,但很少可以对PDF进行标记以便简单可靠地转化成Web友好的格式。

•PDF文档不容易流动,就是说很难适应小屏幕或者对布局进行明显的改变。

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

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

•EPUB中的所有内容基本上都是XML。EPUB文件可使用标准XML工具创建,不需要任何专门或者私有的软件。

•EPUB内容(eBook的具体内容)基本上都是XHTML1.1(另一种格式是DTBook,为视力受限者编码书籍的一种标准。关于DTBook的更多信息请参阅参考资料,本教程中不涉及这部分)。

•大多数EPUBXML模式都来自现成的、可免费获得的、已发布的规范。

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

/////////////////////////////////////////////////////////////////////////////////////////////Page3

创建第一个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的编辑器—具体而言就是能够根据参考资料给出的RelaxNG模式进行验证。

--------------------------------------------------------------------------------

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文件

<?xmlversion="1.0"?>

<containerversion="1.0"xmlns="urn:oasis:names:tc:opendocument:xmlns:container">

<rootfiles>

<rootfilefull-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,即OpeneBookPublicationStructure,但不是必须的)。

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

--------------------------------------------------------------------------------

打开PackagingFormat元数据文件

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

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

清单3.包含示例元数据的OPFcontent文件

<?xmlversion='1.0'encoding='utf-8'?>

<packagexmlns="http://www.idpf.org/2007/opf"

xmlns:dc="http://purl.org/dc/elements/1.1/"

unique-identifier="bookid"version="2.0">

<metadata>

<dc:title>HelloWorld:MyFirstEPUB</dc:title>

<dc:creator>MyName</dc:creator>

<dc:identifierid="bookid">urn:uuid:12345</dc:identifier>

<metaname="cover"content="cover-image"/>

</metadata>

<manifest>

<itemid="ncx"href="toc.ncx"media-type="text/xml"/>

<itemid="cover"href="title.html"media-type="application/xhtml+xml"/>

<itemid="content"href="content.html"media-type="application/xhtml+xml"/>

<itemid="cover-image"href="images/cover.png"media-type="image/png"/>

<itemid="css"href="stylesheet.css"media-type="text/css"/>

</manifest>

<spinetoc="ncx">

<itemrefidref="cover"linear="no"/>

<itemrefidref="content"/>

</spine>

<guide>

<referencehref="cover.html"type="cover"title="Cover"/>

</guide>

</package>

OPF模式与名称空间

OPF文档本身必须使用名称空间http://www.idpf.org/2007/opf,元数据则使用DublinCoreMetadataInitiative(DCMI)名称空间http://purl.org/dc/elements/1.1/。

最好现在将OPF和DCMI模式添加到XML编辑器中。EPUB用到的所有模式都可以下载。

元数据

DublinCore定义了一组常用的元数据,可用于描述各种不同的数字资料,它不是EPUB规范的一部分。所有这些术语都可以出现在OPF元数据部分。编写要分发的EPUB时,这里可以放很多内容,目前来说清单4的内容就足够了。

清单4.OPF元数据摘要

...

<metadata>

<dc:title>HelloWorld:MyFirstEPUB</dc:title>

<dc:creator>MyName</dc:creator>

<dc:identifierid="bookid">urn:uuid:12345</dc:identifier>

<metaname="cover"content="cover-image"/>

</metadata>

...

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

其他和内容相关的可以考虑添加的元数据包括:

•语言(如dc:language)。

•出版日期(如dc:date)。

•出版商(如dc:publisher)。(可以是公司或个人的名称)。

•版权信息(如dc:rights)。(如果采用CreativeCommons许可证,可以将许可证的URL放在这里)。

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

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

Manifest

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

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

清单5.OPFmanifest的一部分

...

<manifest>

<itemid="ncx"href="toc.ncx"media-type="text/xml"/>

<itemid="cover"href="title.html"media-type="application/xhtml+xml"/>

<itemid="content"href="content.html"media-type="application/xhtml+xml"/>

<itemid="cover-image"href="images/cover.png"media-type="image/png"/>

<itemid="css"href="stylesheet.css"media-type="text/css"/>

</manifest>

...

高级OPFmanifest

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

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

EPUB支持四种核心图像文件类型:JointPhotographicExpertsGroup(JPEG)、PortableNetworkGraphics(PNG)、GraphicsInterchangeFormat(GIF)和ScalableVectorGraphics(SVG)。如果能够提供对核心类型的后退转换(fall-back),也可包含不支持的文件类型。关于后退转换内容的更多信息请参阅OPF规范。

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

Spine

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

清单6.OPFspine的一部分

...

<spinetoc="ncx">

<itemrefidref="cover"linear="no"/>

<itemrefidref="content"/>

</spine>

...

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

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

Guide

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

清单7.OPFguide的一部分

...

<guide>

<referencehref="cover.html"type="cover"title="Cover"/>

</guide>

...

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

•cover:图书封面

•title-page:包含作者和出版商信息的页面

•toc:目录

完整的列表请参阅OPF2.0规范(参见参考资料)。

--------------------------------------------------------------------------------

内容的NCX表

NCX和OPF元数据的交叉

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

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

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

清单8.简单的NCX文件

<?xmlversion='1.0'encoding='utf-8'?>

<!DOCTYPEncxPUBLIC"-//NISO//DTDncx2005-1//EN"

"http://www.daisy.org/z3986/2005/ncx-2005-1.dtd">

<ncxxmlns="http://www.daisy.org/z3986/2005/ncx/"version="2005-1">

<head>

<metaname="dtb:uid"content="urn:uuid:12345"/>

<metaname="dtb:depth"content="1"/>

<metaname="dtb:totalPageCount"content="0"/>

<metaname="dtb:maxPageNumber"content="0"/>

</head>

<docTitle>

<text>HelloWorld:MyFirstEPUB</text>

</docTitle>

<navMap>

<navPointid="navpoint-1"playOrder="1">

<navLabel>

<text>Bookcover</text>

</navLabel>

<contentsrc="title.html"/>

</navPoint>

<navPointid="navpoint-2"playOrder="2">

<navLabel>

<text>Contents</text>

</navLabel>

<contentsrc="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匹配。

NCXnavMap

NCX和OPFspine有什么不同?

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

一条法则是NCX包含的navPoint元素通常比OPFspine中的itemref元素多。实际上,spine中的所有项都会出现在NCX中,但NCX可能更详细。

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

•playOrder属性,说明文档的阅读顺序。和OPFspine中itemref元素的顺序相同。

•navLabel/text元素,给出该章节的标题。通常是章的标题或者数字,如“第一章”,或者—像这个例子一样—“封面”。

•content元素,它的src属性指向包含这些内容的物理资源。就是OPFmanifest中声明的文件(也可使用片段标识符引用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)

<htmlxmlns="http://www.w3.org/1999/xhtml">

<head>

<title>HelloWorld:MyFirstEPUB</title>

<linktype="text/css"rel="stylesheet"href="stylesheet.css"/>

</head>

<body>

<h1>HelloWorld:MyFirstEPUB</h1>

<div><imgsrc="images/cover.png"alt="Titlepage"/></div>

</body>

</html>

EPUB的XHTML需要符合几条要求,和一般的Web开发不同:

•内容必须是有效的XHTML1.1:XHTML1.0Strict和XHTML1.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非常支持CSS2@font-face规则,允许内嵌字体。如果创建技术文档,这点可能无关紧要,但是如果用多种语言或针对特定领域编写EPUB,能够指定具体的字体数据就很有必要了。

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

/////////////////////////////////////////////////////////////////////////////////////////////Page4

打包和检查EPUB

现在,应当可以对EPUB包进行打包。这个包可以是您自己创建的一本新书,也可使用从本文下载部分获得的原始文件。

用ZIP打包EPUB文件

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

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

•ZIP档案不能加密。EPUB支持加密,但不是在ZIP文件这一层上。

在类UNIX?操作系统上,使用ZIP2.3可通过两个命令来创建EPUBZIP文件,如清单11所示(这些命令假设当前工作目录为EPUB项目。)

清单11.将EPUB打包成有效的epub+zip文件

$zip-0Xqmy-book.epubmimetype

$zip-Xr9Dqmy-book.epub*

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

--------------------------------------------------------------------------------

EPUB验证

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

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

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

清单12.运行EpubCheck工具程序

$java-jar/path/to/epubcheck.jarmy-book.epub

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

清单13.EpubCheck错误

my-book.epub:imagefileOEBPS/images/cover.pngismissing

my-book.epub:resourceOEBPS/stylesheet.cssismissing

my-book.epub/OEBPS/title.html(7):'OEBPS/images/cover.png':

referencedresourcemissinginthepackage

Checkfinishedwithwarningsorerrors!

这时候可能需要设置CLASSPATH使它指向EpubCheck的安装位置,因为确实需要导入几个外部库。如果得到这样的消息则需要设置CLASSPATH:

org.xml.sax.SAXParseException:noimplementationavailableforschemalanguage

withnamespaceURI"http://www.ascc.net/xml/schematron"

如果验证成功,就会看到“Noerrorsorwarningsdetected(没有检测到错误或警告)”。祝贺您完成了第一个EPUB!

--------------------------------------------------------------------------------

查看EPUB

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

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

图1.ADE中显示的EPUB

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

图2.在Bookworm中显示EPUB

这里的问题在于ADE不支持这种特殊声明。如果数字图书的格式非常重要,那么就必须了解不同阅读软件的特点。

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

/////////////////////////////////////////////////////////////////////////////////////////////Page5

从DocBook到EPUB

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

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

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

清单14.简单的DocBook图书

<?xmlversion="1.0"encoding="utf-8"?`>

<book>

<bookinfo>

<title>MyEPUBbook</title>

<author><firstname>Liza</firstname>

<surname>Daly</surname></author>

<volumenum>1234</volumenum>

</bookinfo>

<prefaceid="preface">

<title>Titlepage</title>

<figureid="cover-image">

<title>OurEPUBcoverimageicon</title>

<graphicfileref="cover.png"/>

</figure>

</preface>

<chapterid="chapter1">

<title>ThisisaprettysimpleDocBookexample</title>

<para>

Notmuchtoseehere.

</para>

</chapter>

<chapterid="end-notes">

<title>Endnotes</title>

<para>

Thisspaceintentionallyleftblank.

</para>

</chapter>

</book>

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

清单15.将DocBook转化成EPUB

$xsltproc/path/to/docbook-xsl-1.74.0/epub/docbook.xsldocbook.xml

WritingOEBPS/bk01-toc.htmlforbook

WritingOEBPS/pr01.htmlforpreface(preface)

WritingOEBPS/ch01.htmlforchapter(chapter1)

WritingOEBPS/ch02.htmlforchapter(end-notes)

WritingOEBPS/index.htmlforbook

WritingOEBPS/toc.ncx

WritingOEBPS/content.opf

WritingMETA-INF/container.xml

定制DocBookXSL

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

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

清单16.从DocBook创建EPUB档案

$echo"application/epub+zip">mimetype

$zip-0Xqmy-book.epubmimetype

$zip-Xr9Dmy-book.epub*

$java-jarepubcheck.jarmy-book.epub

Noerrorsorwarningsdetected

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

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

--------------------------------------------------------------------------------

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

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

可使用不同的PythonXSLT库,我喜欢lxml。它不但提供了XSLT1.0必要的功能,而且解析效率高,完全支持XPath1.0,提供了专门处理HTML的扩展。如果喜欢不同的库或者使用Python以外的编程语言,修改这些例子也很简单。

用lxml调用DocBookXSL

使用lxml调用XSLT的最有效办法是事先解析XSLT,然后创建反复使用的转换器。这样很方便,因为我的DocBook-to-EPUB需要转换多个DocBook文件。如清单17所示。

清单17.使用lxml运行DocBookXSL

importos.path

fromlxmlimportetree

defconvert_docbook(docbook_file):

docbook_xsl=os.path.abspath('docbook-xsl/epub/docbook.xsl')

#GivetheXSLTprocessortheabilitytocreatenewdirectories

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))

DocBookXSL中的EPUB模块创建输出文件本身,因此转换过程什么也不返回。相反,DocBook在当前工作目录中创建了两个文件夹(META-INF和OEBPS),包含转换的结果。

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

DocBookXSL不会对文档中使用的任何图片执行操作,仅仅创建元数据文件和要呈现的XHTML。由于EPUB规范要求content.opfmanifest列出所有资源,可以预料到manifest将寻找原始DocBook文件引用的任何图片。清单18显示了这种技术,其中假定path变量包含DocBookXSLT生成的、当前所处理的EPUB的路径。

清单18.解析OPF内容文件以寻找缺失的资源

importos.path,shutil

fromlxmlimportetree

deffind_resources(path='/path/to/our/epub/directory'):

opf=etree.parse(os.path.join(path,'OEBPS','content.opf'))

#Alltheopf:itemelementsareresources

foriteminopf.xpath('//opf:item',

namespaces={'opf':'http://www.idpf.org/2007/opf'}):

#IftheresourcewasnotalreadycreatedbyDocBookXSLitself,

#copyitintotheOEBPSfolder

href=item.attrib['href']

referenced_file=os.path.join(path,'OEBPS',href):

ifnotos.path.exists(referenced_file):

shutil.copy(href,os.path.join(path,'OEBPS'))

自动创建mimetype

DocBookXSL不会创建mimetype文件,不过清单19中所示的代码可以完成这项任务。

清单19.创建mimetype文件

defcreate_mimetype(path='/path/to/our/epub/directory'):

f='%s/%s'%(path,'mimetype')

f=open(f,'w')

#Becarefulnottoaddanewlinehere

f.write('application/epub+zip')

f.close()

用Python创建EPUB包

现在只需要将文件打包成有效的EPUBZIP包。需要分两步:将未经压缩的mimetype文件作为第一个文件加进去,然后添加其他目录。如清单20所示。

清单20.使用Pythonzipfile模块创建EPUB包

importzipfile,os

defcreate_archive(path='/path/to/our/epub/directory'):

'''CreatetheZIParchive.Themimetypemustbethefirstfileinthearchive

anditmustnotbecompressed.'''

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

#TheEPUBmustcontaintheMETA-INFandmimetypefilesattheroot,so

#we'llcreatethearchiveintheworkingdirectoryfirstandmoveitlater

os.chdir(path)

#Openanewzipfileforwriting

epub=zipfile.ZipFile(epub_name,'w')

#Addthemimetypefilefirstandsetittobeuncompressed

epub.write(MIMETYPE,compress_type=zipfile.ZIP_STORED)

#FortheremainingpathsintheEPUB,addalloftheirfiles

#usingnormalZIPcompression

forpinos.listdir('.'):

forfinos.listdir(p):

epub.write(os.path.join(p,f)),compress_type=zipfile.ZIP_DEFLATED)

epub.close()

好了!切记要进行验证。

/////////////////////////////////////////////////////////////////////////////////////////////Page6

结束语

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

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

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

相关推荐