自从javaei网站推出h2p以来,得到了很多人的支持和鼓励,也给出了很多宝贵意见,再次深表谢意。
这些意见主要是三个方面的问题。第一:为什么要生成pdf;第二:h2p文件分成两个,比较繁琐,为什么不合成一个;第三:h2p-tool由c#和java实现,用起来不够简单,需要进一步完善。这三方面的意见提得非常好,在设计h2p之前,我其实是深思熟虑过的。
为什么要转换成pdf?回答这个问题很简单也很难?我就简单的说一下,首先pdf已成为广泛支持的具有丰富表现力的文档格式;其次pdf是聚合、收藏网络文章的最便利的文档格式,因为其强大的书签功能和瘦小的体积;还有很多,不一一列举了。说到底,h2p就是一个把网络文章整理成pdf的一个完整的解决方案,有些网站也有制作电子书的功能,但是h2p是一个更加通用的解决方案。
关于h2p文件的问题,分成两个文件来描述的确不方便,现在回想起来,当时分成两个文件是考虑的过多了,合并成一个文件迫在眉睫,而这是本文的主要内容。
合并后的h2p文件其后缀为.h2p.xml,主要描述url的信息和url的层次结构,h2p-tool根据h2p文件生成有书签的pdf文档。合并后,对h2p文件的操作变得简单,还可以通过xsl直接展示url的层次结构,而且合作网站对h2p的支持也将变得简单。
经过慎重考虑和仔细设计,h2p文件的一个例子如下:
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="http://www.javaei.com/content/h2p/h2p.xsl"?> <!DOCTYPE book PUBLIC "-//JavaEI/JavaEI h2p Configuration DTD//CN" "http://www.javaei.com/dtd/javaei-h2p.dtd" > <book name="我的PDF书"> <chapter name="163"> <chapter name="163新闻"> <href id="11111"><![CDATA[http://news.163.com]]></href> </chapter> <chapter name="163体育"> <href id="2222"><![CDATA[http://sports.163.com]]></href> </chapter> </chapter> <chapter name="sohu"> <href id="333"><![CDATA[http://www.sohu.com]]></href> <chapter name="sohu新闻"> <href id="444"><![CDATA[http://news.sohu.com]]></href> </chapter> </chapter> </book>
对应的dtd如下:
<!ELEMENT book (chapter+)> <!ATTLIST book name CDATA #REQUIRED> <!ELEMENT chapter (href?,chapter*)> <!ATTLIST chapter name CDATA #REQUIRED> <!ELEMENT href (#PCDATA)> <!ATTLIST href id CDATA #REQUIRED>
利用xsl对该样例文件的解析效果如图:
层次结构的深度是没有限制的,h2p的xsl实现了对xml的解析和树节点的构造,如果对这方面的问题感兴趣的可以参考我这个xsl。合作网站可以提供自己的xsl。Xsl解析xml生成树的核心代码如下:
<xsl:template match="//chapter"> <xsl:for-each select="."> <li> <img class="nodeimg"> <xsl:choose> <xsl:when test="./chapter"> <xsl:attribute name="src">http://www.javaei.com/res/images/closed.gif</xsl:attribute> <xsl:attribute name="onclick">clicknode(this)</xsl:attribute> </xsl:when> <xsl:otherwise> <xsl:attribute name="src">http://www.javaei.com/res/images/leaf.gif</xsl:attribute> </xsl:otherwise> </xsl:choose> </img> <xsl:choose> <xsl:when test="./href"> <a> <xsl:attribute name="href"><xsl:value-of select="./href" /></xsl:attribute> <xsl:attribute name="target">right</xsl:attribute> <xsl:attribute name="class">h2pnodestyle</xsl:attribute> <xsl:value-of select="text()" /><xsl:value-of select="@name" /> </a> </xsl:when> <xsl:otherwise> <xsl:value-of select="text()" /><xsl:value-of select="@name" /> </xsl:otherwise> </xsl:choose> <ul class="collapsed"> <xsl:apply-templates select="./chapter" /> </ul> </li> </xsl:for-each> </xsl:template>
关键是这两句:
<xsl:template match="//chapter">
<xsl:apply-templates select="./chapter" />
这实际上形成了递归调用。
关于h2p-tool的问题,不得不说,这是个难题。要求根据url生成的pdf展现效果与浏览器里展现的效果一致,这无异于做一个浏览器,难度可想而知。在java领域,目前还没找到一个可以用的解决方案,所以才不得不借助于别人的c#的组件。h2p-tool的完善工作将是以后的主要方向,大家如果有好的思路,请不吝赐教。