使用epublib解析epub文件(章节内容、书籍菜单)

2018-10-15 09:22:07

引入epulib包时,一定要引入slf4j包,否则实例化epublib失败都不知道啥原因

前阵子在android上解析epub格式的书籍。发现了这个开源的epub解析库。相关资料甚少!折腾了一阵子,发现其实光使用的话还是挺简单的。真是萌萌哒~下面简单介绍一下epublib。


epublib不仅可以用来解析epub格式的书籍,同样也可以用来生成一本epub书籍。由于我只是用于阅读,所以这里只介绍解析的方法。当然,要想了解epub的解析,首先得对epub格式的规范有一定的认识。


话不多说,进入正题!



(一) 相关资料:


1. 项目地址:

https://github.com/psiegman/epublib


2. 官方api文档:

http://www.siegmann.nl/static/epublib/apidocs/



3. 官方网站:

http://www.siegmann.nl/epublib 



4. Android上使用需要用到的依赖 

Slf4j-android : http://www.slf4j.org/android/ 

epublib-core-latest.jar  :  https://github.com/downloads/psiegman/epublib/epublib-core-latest.jar


5. 使用epublib的开源android项目

PagerTurner (这个以后可能会开一个篇章简单介绍一下)





(二)重要的类:


1. Book 

—— 表示一本书。书籍的内容全在这里。通过book对象能过获得各类书籍内容,如resource,Metadata等;



2.Resource

—— 所有的resource对象构成一本书。所以,一个Resource就是书籍的一部分资源,这资源信息可以是html,css,js,图片等;


3.MetaData

—— 书籍的头信息。比如,作者,出版社,语言等;


4.Spine

—— 书籍的阅读顺序,是一个线性的顺序。通过Spine可以知道应该按照怎样的章节(注:这里所说的章节其实就是resource,不仅是书籍文本内容哦~下同)顺序去阅读,并且通过Spine可以找到对应章节的内容。


形式如:



5.TableOfContent

—— 这个与Spine有所区别。同样可以访问到各个章节的内容。但是他是树形结构。

形式如:






6.Resources

——获得全部的Resource对象。然后通过Resources对象能够轻易的取出你想要查找的Resource对象,可以用于查找Resource.


可以通过id或者href来定位resource,也可以通过MediaType类型来获得指定resource。部分重要方法如下图所示:


7.MediaType

—— Resource的类型描述。用于说明此Resource是何种类型(CSS/JS/图片/HTML/ VEDIO等)。


8.MediatypeService

—— 这个类中就包含了各种MediaType类型。如下图所示:


(三)基本用法

1.读取一本书


(1)最简单的方法就是直接从流中读取书籍


try {

    EpubReader reader = new EpubReader();

    InputStream in = aciticity.getAssets().open("1.epub");

    reader.readEpub(in);

} catch (Exception e) {

    e.printStackTrace();

}

1

2

3

4

5

6


(2)加载速度太慢?图片。视频之类的就先不读取了。

  try {

            EpubReader epubReader = new EpubReader();


        MediaType[] lazyTypes = {

                 MediatypeService.CSS,  

                 MediatypeService.GIF, MediatypeService.JPG,

                 MediatypeService.PNG,

                 MediatypeService.MP3,

                 MediatypeService.MP4};

        String fileName = "1.epub";

        Book book = epubReader.readEpubLazy(fileName,"UTF-8",Arrays.asList(lazyTypes));


    } catch (Exception e) {

        e.printStackTrace();

    }

1

2

3

4

5

6

7

8

9

10

11

12

13

14


2.获取章节内容

(1)获取所有章节内容。

 List<Resource> contents = book.getContents();


       (2)获取某一章的章节内容。


 //通过index获取

int index = 0;

Resource byIndex = book.getSpine().getResource(index);


//通过href获取

String href = "/images/1.png";

Resource byHref = book.getResources().getByHref(href);


//通过id

String id = "chapter01"; 

Resource byId = book.getResources().getById(id);


//特殊的resource,可以直接获取

book.getCoverImage();

book.getCoverPage();

book.getNcxResource();

book.getOpfResource();


//其他

book.getSpine().getSpineReferences().get(0).getResource();

book.getGuide().getReferences().get(0).getResource();

                    

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

3.获取书籍菜单

(1)两种不同的菜单

//通过spine获取线性的阅读菜单,此菜单依照阅读顺序排序

List<SpineReference> spineReferences = book.getSpine().getSpineReferences();

//获取对应resource

pineReferences.get(0).getResource();


//通过TableOfContents获取树形菜单。此菜单按照章节之间的关系(树形)排序

TableOfContents tableOfContents = book.getTableOfContents();

//获得对应的reource

tableOfContents.getTocReferences().get(0).getResource();

1

2

3

4

5

6

7

8


其中,对于TableOfContent,接下来给出参考的遍历方式。


首先,是菜单的JavaBean:

/**

 * 菜单,包含了标题,href,儿子节点

 * @author Administrator

 *

 */

public class ContentItem{


    private String title;

    private String url;//href

    private int size;//resource的大小


    //孩子节点

    private List<ContentItem> children;


    public ContentItem() {

        super();

    }


    public ContentItem(String title, String url,int size) {

        super();

        this.title = title;

        this.url = url;

        this.size = size;

    }


    public String getTitle() {

        return title;

    }


    public void setTitle(String title) {

        this.title = title;

    }


    public String getUrl() {

        return url;

    }


    public void setUrl(String url) {

        this.url = url;

    }


    public List<ContentItem> getChildren() {

        if(this.children==null){

            children = new ArrayList<ContentItem>();

        }

        return children;

    }


    public void setChildren(List<ContentItem> children) {

        this.children = children;

    }


    public int getSize() {

        return size;

    }


    public void setSize(int size) {

        this.size = size;

    }


}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60


上面contentItem中的url就是href,到时候需要加载具体章节的内容的话,只需要根据href就可以拿到指定的resource了。


然后,通过TableOfContents,遍历出我们想要的树形菜单。


public class EpubMenuParser {


    private ContentItem menu = new ContentItem();


    public ContentItem startParse(Book book){

        //从深度为0开始遍历

        parseMenu(book.getTableOfContents().getTocReferences(), 0);

        return menu;


    }


    /**

     * 遍历epub书籍的目录

     * @param refs 

     * @param level 菜单深度

     */

    private void parseMenu(List<TOCReference> refs, int level) {


        if (refs == null || refs.isEmpty()) {

            return;

        }


        for (TOCReference ref : refs) {


            if (ref.getResource() != null) {

                if (level == 0) {

                    // 第一层,一级节点,父节点是root

                    ContentItem item = new ContentItem(ref.getTitle(),

                             ref.getCompleteHref(),(int)ref.getResource().getSize());

                    menu.getChildren().add(item);


                } else if (level == 1) {


                    int lastIndexOf_depth1 = menu.getChildren().size() - 1;// 当前最后一个一级节点的位置


                    // 存入root的孩子节点中的最后一个一级节点中

                    ContentItem item2 = new ContentItem(ref.getTitle(),

                            ref.getCompleteHref(),(int)ref.getResource().getSize());


                    menu.getChildren().get(lastIndexOf_depth1).getChildren()

                            .add(item2);


                } else if (level == 2) {


                    int lastIndexOf_depth1 = menu.getChildren().size() - 1;// 当前最后一个一级节点的位置

                    int lastIndexOf_depth2 = menu.getChildren()

                            .get(lastIndexOf_depth1).getChildren().size() - 1;// 当前最后一个二级节点的位置


                    // 父节点为二级节点中的最后一个节点

                    ContentItem item = new ContentItem(ref.getTitle(),

                        ref.getCompleteHref(),(int)ref.getResource().getSize());


                    menu.getChildren().get(lastIndexOf_depth1).getChildren()

                            .get(lastIndexOf_depth2).getChildren().add(item);

                }

            }

            //继续遍历它的儿子

            parseMenu(ref.getChildren(), level + 1);

        }

    }


}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62


当然,这个遍历方法还是有点问题的。比如,目前的写法只支持3级菜单。不过一般的都够用了。当然,写死了并不好,根据需求而定哦~

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

作者:sonnyching 

来源:CSDN 

原文:https://blog.csdn.net/sonnyching/article/details/47407549?utm_source=copy 

版权声明:本文为博主原创文章,转载请附上博文链接!

  • 2020-12-14 15:06:50

    youtube-dl视频下载神器

    youtube-dl 是一款命令行下的视频下载工具,看着名称像是 YouTube 下载工具,其实这款工具不仅支持 YouTube ,还支持非常多的视频网站,比如优酷、爱奇艺、 bilibili 等,在写这篇日志的时候,暂时不支持腾讯视频。

  • 2020-12-15 20:06:43

    更多WebTorrent例子

    WebTorrent是第一个运行在浏览器的Torrent客户端。是的,没错。就是浏览器! 它完全是用JavaScript编写的,并使用WebRTC实现了真正的点对点传输。不需要浏览器插件、扩展或安装。 使用开放的Web标准,WebTorrent将网站用户连接在一起,形成一个分布式的、分散的Browser-to-browser网络,以实现高效的文件传输。

  • 2020-12-16 06:43:06

    WebRTC 实现Android点到点互连(含Demo)

    WebRTC被誉为是web长期开源开发的一个新启元,是近年来web开发的最重要创新。WebRTC允许Web开发者在其web应用中添加视频聊天或者点对点数据传输,不需要复杂的代码或者昂贵的配置。目前支持Chrome、Firefox和Opera,后续会支持更多的浏览器,它有能力达到数十亿的设备。

  • 2020-12-16 22:04:03

    基于本地代理的边下边播技术分析

    我们熟知的边下边播技术,是迅雷提供的,还有之前的快播、快车等工具,它们使用的技术基本上都是P2P下载技术。 P2P下载技术,本质上它并不是C-S的架构,P2P----> Peer to Peer,实际上它将各个客户端的资源调度起来,给上传资源种子,方便后续的下载者可以快速有效的下载资源,这种方式需要服务器整合各个Client,在有用户需要下载的情况下,服务器能及时调度资源,开始给下载者提供资源信息,保证下载者下载资源越快越好。P2P的下载方式后面我们专门介绍一下。这儿不继续展开了。

  • 2020-12-16 22:07:44

    Android视频点播-边播边缓存

    一些知名的视频app客户端(优酷,爱奇艺)播放视频的时候都有一些缓存进度(二级进度缓存),qq,微信有关的小视频,还有一些短视频app,都有边播边缓的处理。还有就是当文件缓存完毕了再次播放的话就不再请求网络了直接播放本地文件了。既节省了流程又提高了加载速度。 今天我们就是来研究讨论实现这个边播边缓存的框架,因为它不和任何的业务逻辑耦合。

  • 2020-12-16 22:46:44

    基于coturn项目的stun/turn服务器搭建

    webrtc是google推出的基于浏览器的实时语音-视频通讯架构。其典型的应用场景为:浏览器之间端到端(p2p)实时视频对话,但由于网络环境的复杂性(比如:路由器/交换机/防火墙等),浏览器与浏览器很多时候无法建立p2p连接,只能通过公网上的中继服务器(也就是所谓的turn服务器)中转。示例图如下:

  • 2020-12-16 23:06:05

    Rocket.Chat推送信息

    Rocket.Chat推送消息 Rocket.Chat是一个开源实时通讯平台, 支持Windows, Mac OS, Linux. 支持聊天, 文件上传, 视频通话, 语音通话功能. 向Rocket.Chat推送消息 以下示例可以转为别的语言的版本, 本示例使用Linux平台的curl测试, curl非常强大. 登陆 首先需要登陆Rocket.Chat服务器