使用 FOP将中文DocBook xml转换成pdf的实现记录

http://blog.donews.com/limodou/archive/2004/04/01/9917.aspx

中文的确是一个很头痛的问题。在顺利将XML 写成的DocBook文档转换成HTML之后,我面临的下一个挑战就是如何将其转换为PDF。如果是英文的文档,一切都很OK。将xsl改为 fop/docbook.xsl,然后执行fop -fo your.fo -pdf your.pdf即可,但在转换中文上,却不是这么简单。

我与weck朋友关于转换的问题经过了一系统的尝试。大家可以看看我俩的讨论:

reStructuredText 研究

其实,让FOP支持中文字体还算容易,如何转换可以参考weck写的方法:

用 FOP将DocBook输出为PDF文档

不过,转换后的pdf文档的中文断字有问题,有些行还没有结束就跳到了下一行上去了。结果为了解决中文断字的问题我查了好多地方都无功则返。weck也转成使用DocBook in ConText来转换DocBook 文档了(不过,DocBook in ConText是直接处理XML文档,而不是生成的xsl-fo文档,这样效果与标准的DocBook相差很大;而且还要用到Tex,那也是一件不小的工程。)

于是在感慨之余,我写了一篇可怜的中文!,用来表示我的感叹。不过,有位SummerRain
朋友给我留了个言,告诉我如何解决中文断字的方法:就是将fo文件中的language都设为zh即可。非常感谢他,在经过我的又一番试验之后,中文断字就算是解决了。下面就我的实验记录如下:

1. 如何从原始的xml变成xsl-fo后,使得language=”zh”生效。

SummerRain朋友的方法是在xsl-fo文件中加入language=”zh”,但这个xsl-fo文件不是我的源始文档,它是从原始的xml经过转化后生成的,因此直接修改xsl-fo的方法不适合。如果大家看过我写的《DocBook 学习》教程,上面讲述了如何支持中文的方法(我使用的方法)。我简单地描述一下:

    • 使用utf-8编码,文件也要用utf-8编码保存
    • 使用<xsl:param name=”l10n.gentext.language” select=”‘zh_cn’”/>参数设置

zh_cn是docbook-xsl中定义好的中文相关的信息文件,它可以将docbook-xsl转换xml后生成的一些标准用语变成中文,如 “Table of Contents”就变成“目录”了。那么在转换xsl-fo文件时也使用这一参数,一方面也起到上述作用,另一方面,你打开生成的xsl-fo文件后,会看到language=”zh_cn”。也就是说在xsl-fo中已经加入了language=”zh_cn了”。不过不是zh。那么结果就是,断字依然有问题。如果一步到位呢?没办法,我只好将docbook-xsl中的common/zh_cn.xml文件拷贝到common/zh.xml。然后在 common/l10n.xml中加入了zh.xml的entity定义和它的引用。还要将common/zh.xml文件开始处的 language=”zh_cn”改为language=”zh”。这样,我们把上面的select=”zh_cn”改为select=”zh”就行了。再生成xsl-fo文件,打开后会看到language的值为”zh”了。

这样断字问题基本解决。

2. 未解决的问题

但是还有一些问题没有解决,也许有好心人会帮助我。我列在下面:

  • 有些中文标点是不能在句首的,但FOP可不管这一套,因此如何避免标点符号出现在句首?
  • Bookmark中二级以后的标题看不到,但文档正文中的标题都正常。
  • 没有斜体
  • 如何使用中文Type1字体
  • 有些样式出不来,如设置bullet前面的点的样式,在生成pdf后都是圆点。

3. 要注意问题

  • 表格的宽度不能象生成HTML一样。因为HTML会自动调整表格的宽度,而FOP不行,它是很精确的,因此只能多试,宽度的比例一定要合适。
  • 如果是原样输出的话,一行太长不会自动折行,这样出伸出纸张的边缘,因此对于象程序清单、命令行之类的原样输出内容要加入换行。

下面附上我所用的转换驱动样式表内容,大家可以自行测试:

<?xml version=’1.0′?>
<xsl:stylesheet xmlns:xsl=”http://www.w3.org/1999/XSL/Transform
version=”1.0″>

<xsl:import href=”../docbook-xsl/fo/docbook.xsl”/>

<xsl:param name=”body.font.family”>simsun</xsl:param>
<xsl:param name=”monospace.font.family”>simsun</xsl:param>
<xsl:param name=”title.font.family”>simhei</xsl:param>
<xsl:param name=”saxon.character.representation” select=”‘native’”/>
<xsl:param name=”admon.graphics” select=”1″/>
<xsl:param name=”section.autolabel” select=”1″/>
<xsl:param name=”section.label.includes.component.label” select=”1″/>
<xsl:param name=”table.borders.with.css” select=”1″/>
<xsl:param name=”use.extensions” select=”1″/>
<xsl:param name=”tablecolumns.extension” select=”0″/>
<xsl:param name=”callout.unicode” select=”1″/>
<xsl:param name=”callout.unicode.start.character” select=”10102″></xsl:param>
<xsl:param name=”variablelist.as.blocks” select=”1″></xsl:param>
<xsl:param name=”callout.graphics” select=”0″/>
<xsl:param name=”fop.extensions” select=”1″/>
<xsl:param name=”hyphenate”>false</xsl:param>
<xsl:param name=”l10n.gentext.default.language” select=”‘zh’”/>
<xsl:param name=”paper.type” select=”‘A4′”/>
<xsl:param name=”draft.mode” select=”‘no’”/>
<xsl:param name=”generate.toc”>
appendix toc
article/appendix nop
article toc,title
book toc,title
chapter nop
part toc,title
preface toc,title
qandadiv toc
qandaset toc
reference toc,title
sect1 nop
sect2 nop
sect3 nop
sect4 nop
sect5 nop
section nop
set toc,title
</xsl:param>

</xsl:stylesheet>

归类于: DocBook/XML — limodou @ 3:12 pm 评论(23)

23条评论
  1. 您好! 我刚对XML Docbook产生兴趣,正准备开始学,昨天找到一份中文教程,正在称颂Google呢!今天就发现原先就是您的大作!
    http://pyrecord.freezope.org/docbook/index.html

    以后会经常来这里学习!:)

    自来水冲咖啡 —— 2004年04月01日 @6:38 pm

  2. 哈哈。欢迎与我交流。

    limodou —— 2004年04月01日 @9:22 pm

  3. 多谢,我也参考了你不少经验。
    fop的那个bug,我已经提交了patch给fop的bugzilla.

    我的更进一步的探索在这里:
    http://www.blogcn.com/user6/caoxg/index.html?id=2402234&run=.0A0B923

    曹晓钢 —— 2004年06月22日 @2:21 am

  4. 呵呵,我hack了一下fop,总结了一下,放在这篇文章里:
    http://www.redsaga.com /mambo/content/view/17/2/因为要给Hibernate的人看,写的是英文。但是很简单。

    基本上已经可以比较完整的实现docbook+fop生成pdf的问题了。问题还有两个,一个是不知道为什么acrobat reader的菜单中,第二级菜单开始就变成了乱码。这个不影响使用,估计是Acrobat reader的问题,或者fop生成的问题。二是生成的docbook, 文章标题中的中文仍然是乱码。这个应该是docbook标记生成的问题。

    我第一个参考的就是你的这篇blog,给了我很大帮助,也在这里做个连接~

    曹晓钢 —— 2004年07月24日 @6:21 pm

  5. 好。
    其实有阵时间很相仔细研究一下fop的,但由于平时不用java,很多东西还不是很清楚,因此就放弃了。希望有机会好好学习一下fop。

    limodou —— 2004年07月24日 @9:44 pm

  6. Hi,曹晓钢,
    Quoted from your post:"二是生成的docbook, 文章标题中的中文仍然是乱码。",
    For this problem,you have to set your xsl stylesheet as following:

    <xsl:param name="title.font.family">Your Chinese Font</xsl:param>
    <xsl:param name="title.fontset">Your Chinese Font</xsl:param>

    It should be OK to just set title.fontset,however pratically,you have to set both.I guess it must be a bug of the DocBook FO stylesheet.

    Hugh —— 2005年01月26日 @11:47 am

  7. 因为xml的编码(即encoding)不是随便改的,需要与真正的内容对应,即如果你将encoding改为utf-8,则需要将文本真正存成utf-8才行。而不是简单地将big5改为utf-8就完了。

    limodou —— 2005年05月27日 @9:11 am

  8. Hi,你好,我在FOP中遇到一个问题:
    原是可以显示中文的,现在我将JSP产生fo文件的encoding="big5"改为utf-8,
    转换PDF中显示错误:org.apache.fop.apps.FOPException: Invalid byte 1 of 1-byte UTF-8 sequence.
    这可能是什么原因?

    RN —— 2005年05月27日 @1:43 am

  9. Hi limodou,

    I search google for convert chinese docbook to pdf, than got your website. I found we are a lot in common. so I leave a message here(because there is no email of you).
    Hoping to keep in touch with you.

    I am interested in docbook, and now using docbook to write/translate some articles.

    Here is my translated article of http://www.sergiopereira.com/articles/prototype.js.html

    https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html

    Regards

    - sunfmin

    sunfmin —— 2005年09月11日 @10:01 pm

  10. thanks I’ll check the url.

    limodou —— 2005年09月11日 @10:22 pm

  11. 我使用perl html2pdf: http://wiki.perlchina.org/main/show/html2pdf+%E4%B8%AD%E6%96%87%E5%A4%84%E7%90%86

    chiesa —— 2005年09月12日 @12:05 pm

  12. 请问docbook中,programlisting标签中的字体叫什么?由于把中文放在programlisting里面,但我只注册了三种字体,分别是SimSun、simhei、simfang,除了programlisting标签里的显示“#”外,别的都显示正常,我觉得这个字体比较象courire New,尝试了一下,但是也不行。

    tyllr —— 2006年02月02日 @8:42 pm

  13. 不知道。是打印机体,我也搞不清。

    limodou —— 2006年02月03日 @8:15 pm

  14. 中文字体用SimSun不错,但是英文字体不好看,可不可以为中文和英文分别指定字体?

    Daniel —— 2006年06月08日 @5:40 pm

  15. 不知诸位讨论的是FOP的哪个版本?
    我在FOP 0.25下使用中文没有问题,在FOP1.92下一直提示所用字体找不到的错误,不知有谁知道是何原因?

    mumu —— 2006年10月03日 @11:22 am

  16. 对于很长在block内的字符串如何换行呢???

    fins —— 2007年01月29日 @8:05 pm

  17. FOP 0.93不支持嵌入TTF字体,也就是宋体,可以参见:
    fop-0.93/docs/0.93/configuration.pdf中的这句:

    Embedding
    Note
    The PostScript renderer does not yet support TrueType fonts, but can embed Type 1 fonts.

    丁丁 —— 2007年02月23日 @7:27 pm

  18. 关于如何快速搭建FOP 0.20.5,以便支持中文,我也写了一篇blog,顺便也集成了limodou的Docbook学习的xml源文件,作为pdf生成的测试,多谢你了 limodou ^_^
    http://www.cnblogs.com/ericguo/archive/2007/02/25/fop_20_5_chinese_patch.html

    丁丁 —— 2007年02月25日 @4:34 am

  19. fop0.94 是支持 ttf 的

    4. fop 0.94 制作字库
    1. 官网上的命令,一些 lib\**.jar 是没有带版本号的,实际使用需要根据本机情况带上版本号
    2. ttc 需要加 -ttcname,simsun.ttc 对应的是 SimSun,区分大小写
    F:\document\install\fop-0.94>java -cp build\fop.jar;lib\avalon-framework-4.2.0.jar;lib\commons-logging-1.0.4.jar;lib\commons-io-1.3.1.jar org.apache.fop.fonts.apps.TTFReader -ttcname SimSun C:\WINDOWS\Fonts\simhei.ttf simhei.xml
    3. fop.xconf 中 font 的 metrics-url 和 embed-url 要用 file:///f:/ 的形式,不能用 f:\
    4. 转换时要用 -c 指定一下 ./fop -c conf/fop.xconf

    [email protected]

    楼主是否可以回复一下,怎样设 pdf 中表格的宽度??

    leonzhu211 —— 2007年08月30日 @3:57 pm

  20. 請問一下,如何把放有中文字的xsl-fo檔案變成pdf呢?
    xsl-fo檔案如下:
    <?xml version="1.0" encoding="utf-8"?>

    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">

    <!– defines the layout master –>
    <fo:layout-master-set>
    <fo:simple-page-master master-name="first"
    page-height="29.7cm"
    page-width="21cm"
    margin-top="1cm"
    margin-bottom="2cm"
    margin-left="1.5cm"
    margin-right="1cm">
    <fo:region-body margin-top="1cm"/>
    <fo:region-before extent="3cm"/>
    <fo:region-after extent="1.5cm"/>
    </fo:simple-page-master>
    </fo:layout-master-set>
    <!– starts actual layout –>
    <fo:page-sequence master-reference="first">

    <fo:flow flow-name="xsl-region-body">

    <!– table start –>
    <fo:table table-layout="fixed" width="100%" border-collapse="separate">
    <fo:table-column column-width="40mm"/>
    <fo:table-column column-width="40mm"/>
    <fo:table-column column-width="40mm"/>
    <fo:table-column column-width="40mm"/>
    <fo:table-body>
    <fo:table-row>
    <fo:table-cell number-columns-spanned="4"><fo:block font-family="Helvetica" font-size="9pt" text-decoration="underline" font-weight="bold" font-style="italic">ORDER INFORMATION</fo:block></fo:table-cell>
    </fo:table-row>
    <fo:table-row>
    <fo:table-cell><fo:block font-family="Helvetica" font-size="8pt" font-weight="bold">一二三</fo:block></fo:table-cell>
    <fo:table-cell><fo:block font-family="Helvetica" font-size="8pt">一二三</fo:block></fo:table-cell>
    <fo:table-cell><fo:block font-family="Helvetica" font-size="8pt" font-weight="bold">一二三</fo:block></fo:table-cell>
    <fo:table-cell><fo:block font-family="Helvetica" font-size="8pt">Success</fo:block></fo:table-cell>
    </fo:table-row>
    </fo:table-body>
    </fo:table>
    </fo:flow>
    </fo:page-sequence>
    </fo:root>

    command line:
    fop testing.fo testing.pdf

    出現以下exception

    javax.xml.transform.TransformerException: org.xml.sax.SAXParseException: Invalid byte 1 of 1-byte UTF-8 sequence.
    at org.apache.fop.cli.InputHandler.transformTo(InputHandler.java:217)
    at org.apache.fop.cli.InputHandler.renderTo(InputHandler.java:125)
    at org.apache.fop.cli.Main.startFOP(Main.java:166)
    at org.apache.fop.cli.Main.main(Main.java:197)

    新手 —— 2008年08月21日 @10:43 am

  21. 第一部分我觉得很奇怪,把zh_cn改成zh,就能解决断定问题,没有对其作任何修改,那究竟是什么原因导致的呢?
    我曾经用docbook组织过一些文档(如,springlive 的全书中文翻译),但fop的中文输出浪费了我太多的时间,最终放弃了。现在使用rendex.com的xep个人版来处理。相对来说,它的字体配置很简单,中文效果也比fop好很多,但它是商业软件,生成文档下面会一个链接到renderX的网站。

    hantsy —— 2009年01月23日 @12:18 am

你可能感兴趣的:(xml)