摘要:XML(eXtensible Stylesheet Language)是目前流行的內容存儲格式,而PDF(Portable Document Format)是電子文檔的內容載體格式,如何將XML文檔轉換成PDF及其他一些用于顯示的文檔格式越來越受到人們的關注。FOP(格式對象處理器Formatting Objects Processor)是由James Tauber開發的一個開源項目,目的是利用XSL-FO將XML文檔轉換成PDF、TXT、DOC等文檔,該文僅以PDF文檔為例,介紹如何利用FOP將XML文檔轉換為其他文檔格式。
關鍵詞:XML;XSL-FO;XSLT;FOP;文檔轉換
中圖分類號:TP311文獻標識碼:A文章編號:1009-3044(2008)29-0425-04
Transformation from XML to other Document Format Based on XSL-FO
WANG Mei-juan1, SHI Ya-qing1, ZHAO Gai-lian2
(1.School of Science,PLA University of Science and Technology,Nanjing 211101,China;2.College of Information Engineering,Yangzhou Polytechnic College,Yangzhou 225000,China)
Abstract: XML(eXtensible Stylesheet Language) is used for data management,which is popular now;while PDF(Portable Document Format)is used for presenting electronic documents.The transformation from XML to PDF and other document format become more and more necessary. FOP(Formatting Objects Processor) is developed by James Tauber,this paper introduces using FOP to transform from XML documents to other documents like PDF by XSL-FO.
Key words: XML; XSL-FO; XSLT; FOP; document transformation
1 引言
XML適合于描述文檔結構和內容,PDF適合于維護電子化頁面視圖描述,網絡中應用背景的不同使文檔的組織方式和表現方式差異很大,為了實現文檔內容的共享和協作,必須進行文檔格式間的轉換。XML文檔轉換為PDF文檔需要兩個基本步驟,如圖1所示。
首先是用XSLT(可擴展樣式表語言轉換eXtensible Stylesheet Language Transformation)樣式表將XML文檔轉換為XSL-FO(可擴展樣式表格式化對象eXtensible Stylesheet Language-Format Object)元素構成的文檔;
其次是用FOP顯示引擎將XSL-FO元素轉換為PDF文檔。
2 XSLT轉換及XSL-FO文檔
2.1 XSLT規范及其文檔結構
XSLT語言由萬維網聯盟定義,最早設計的用意是將XML文檔轉換為其它文檔。隨著XML日益廣泛地用作電子商務中的數據互換語法,對于應用程序將數據從一個XML詞匯表轉換到另一個XML詞匯表的需求也在不斷增加。因此,必須能夠將一種XML數據格式轉換為另一種XML數據格式,而XSLT就是用來實現這種轉換功能的語言。
1) //hello_xsl.xml:
2) <?xml version=\"1.0\"?>
3) <?xml-stylesheet type=\"text/xsl\" href=\"hello.xsl\"?>
4) <p>Hello world</p>
這是一個簡單的XML文檔,用XSLT將這個XML文檔轉換成為可以通過FOP顯示的XSL-FO文檔,XSLT的具體語法規則可以參考http://www.w3.org/TR/xsl/Overview.html。
1) //hello_fo.xsl:
2) <?xml version=\"1.0\"?>
3) <xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">
4) <xsl:template match=\"p\">
5) <fo:root xmlns:fo=\"http://www.w3.org/1999/XSL/Format\">
6) <fo:layout-master-set>
7) <fo:simple-page-master master-name=\"my_page\" margin=\"0.5in\">
8)<fo:region-body/>
9) </fo:simple-page-master>
10) </fo:layout-master-set>
11)<fo:page-sequence master-reference=\"my_page\">
12) <fo:flow flow-name=\"xsl-region-body\">
13) <fo:block>-<xsl:value-of select=\".\"/>-</fo:block>
14) </fo:flow>
15)</fo:page-sequence>
16) </fo:root>
17) </xsl:template>
18) </xsl:stylesheet>
經過XSLT轉換后的XML文件符合XSL-FO的規范。
2.2 XSL-FO規范及其文檔結構
XSL-FO文檔仍是XML格式的文檔,它的命名空間由W3C 站點定義,可以包含任何在這個命名空間中的元素。XSL-FO文檔定義了制作高質量可打印文檔時非常重要的幾件事情:頁面的實際大小的信息(信紙或者A4等);頁邊距(頂部,左邊,底部和右邊)、頁眉、頁腳和頁面其它特性的信息;文本的字體、字體大小、顏色和其它特征的信息;要打印的實際文本,由描述段落、突出顯示、表等類似物的元素來標記。
XSL-FO文檔結構非常簡單,如圖2所示。
<fo:root>元素是XSL-FO文檔的根元素。<fo:layout-master-set>元素指定了頁面定義。通常,根元素包含一個頁面定義,一個頁面定義包含一個或多個<fo:simple-page-master>元素定義的特定頁面的布局,并可以通過<fo:page-sequence>來調用。<fo:page-sequence>元素定義了文檔內使用的頁面布局的序列,其master-reference屬性對應了<fo:simple-page-master>元素中定義的master-name屬性,如果所使用的master-reference在XSL-FO文檔中沒有定義,就會產生錯誤。
用于格式化內容的兩個主要XSL-FO元素是<fo:block>和<fo:inline>。<fo:block>是最基本的元素,用于格式化一個文本塊,類似于HTML中的<p>元素。而<fo:inline>用于定義一些新的文本特性,例如斜體顯示一段文字中的幾個單詞。
由上述XML例子轉換得到的XSL-FO文檔如下:
1) //hello.fo
2) <?xml version=\"1.0\" encoding=\"utf-8\"?>
3) <fo:root xmlns:fo=\"http://www.w3.org/1999/XSL/Format\">
4)<fo:layout-master-set>
5) <fo:simple-page-master master-name=\"A4\" margin-top=\"36pt\" margin-bottom=\"36pt\" page-width=\"21cm\" page-height=\"29.7cm\" margin-left=\"72pt\" margin-right=\"72pt\">
6)<fo:region-body margin-bottom=\"50pt\" margin-top=\"50pt\"/>
7)</fo:simple-page-master>//定義A4紙張
8)</fo:layout-master-set>
9) <fo:page-sequence master-reference=\"A4\">
10) <fo:flow flow-name=\"xsl-region-body\">
11) <fo:block font-size=\"14pt\" line-height=\"17pt\">Hello World</fo:block>
12) </fo:flow>
13) </fo:page-sequence>
14) </fo:root>
3 FOP設計方案
FOP是一個基于XSL-FO的打印格式處理器,也是第一個與輸出無關的格式處理器。該工具的原始版本由James Tauber開發,是一個源碼開放的JAVA API,使用格式化樹結構轉換XML數據到其他格式。FOP有3種使用方式,命令行、程序嵌入和XT 嵌入。本文采取的是第二種程序嵌入。
3.1 FOP下載
FOP可以從FOP發布目錄上面下載。下載網址是http://apache.justdn.org/xml/fop/,下載文檔是一個gzip 文檔包,它包括兩個發行包。其中fop-0.20.5-src發行包包含源代碼,使用它可以自己用Ant進行編譯;fop-0.20.5-bin發行包包含了運行部分。將FOP 軟件包fop-0.20.5rc2-bin.tar.gz解壓縮到d:\\fop即可。其CLASSPATH路徑可以在后面JAVA的設置中進行。也可以直接在MSDos中用命令行設置,本文的實驗是在環境變量中設置的(參見下面JAVA的安裝設置):set classpath=.;d:\\fop\\build\\fop.jar;d:\\fop\\lib\\avalon-framework-cvs-20020806.jar;d:\\fop\\lib\\batik.jar;d:\\fop\\lib\\xalan-2.4.1.jar;d:\\fop\\lib\\xercesImpl-2.2.1.jar;d:\\fop\\lib\\xml-apis.jar;(所有命令均在一行)
3.2 JAVA虛擬機下載安裝與設置
FOP是一個JAVA接口,所以轉換的過程需要用到JAVA虛擬機。可以在http://java.sun.com/j2se/1.4.2/download.html下載最新版本的J2SE1.4.2。下載后安裝在c:\\j2sdk,然后配置其路徑。在“控制面板”的“系統”屬性中,選擇“高級”欄下的“環境變量”按鈕進行設置,查看屬性JAVA_HOME,PATH和CLASSPATH(大小寫無所謂),若已存在則點擊“編輯”,否則點擊“新建”:
· JAVA_HOME:指明JDK安裝路徑,就是剛才安裝時所選擇的路徑c:\\j2sdk,此路徑下包括lib,bin,jre等文檔夾;
· PATH:使得系統可以在任何路徑下識別JAVA命令,設為:
%JAVA_HOME%\\bin;%JAVA_HOME%\\jre\\bin
· CLASSPATH:加載類路徑,只有類在CLASSPATH中,JAVA命令才能識別,設為:
.;%JAVA_HOME%\\lib;%JAVA_HOME%\\lib\ools.jar;d:\\fop\\build\\fop.jar;d:\\fop\\lib\\avalon-framework-cvs-20020806.jar;d:\\fop\\lib\\batik.jar;d:\\fop\\lib\\xalan-2.4.1.jar;d:\\fop\\lib\\xercesImpl-2.2.1.jar;d:\\fop\\lib\\xml-apis.jar; (要加.表示當前路徑,%JAVA_HOME%就是引用前面指定的JAVA_HOME,這里面也包含FOP的路徑);
在“開始”中點擊“運行”,鍵入“cmd”,在MSDos環境下鍵入命令“java -version”,即可查看到安裝信息 。
3.3 生成PDF文檔
FOP的主要意圖是處理XSL-FO文檔,它也能夠通過一個XSLT樣式表完成已有數據文檔(XML)的轉換。FOP 將會把這些信息轉換成一篇臨時的XSL-FO文檔并且最終生成期望的輸出。
以上的三個例子hello.fo,hello_xsl.xml,hello_fo.xsl均保存在FOP的安裝目錄d:\\fop下,并在MSDos窗口中將命令行轉到d:\\fop下:
對于獨立的XSL-FO文檔鍵入命令:
>fop hello.fo hello1.pdf
則將XSL-FO文檔轉換為對應的PDF文檔;
對于由XSLT轉換XML的XSL-FO文件鍵入命令:
>fop -xml hello_xsl.xml -xsl hello_fo.xsl -pdf hello2.pdf
則通過XSLT和FOP將XML文檔轉換為PDF文檔,其中XSL-FO文檔是作為中間過渡過程。
可以得到在d:\\fop下顯示Hello World的PDF文檔,不同的是hello2.pdf比hello1.pdf中多了“――”符號,這正是XSLT樣式表定義的結果。
4 中文字體的嵌入
東方字符的顯示在FOP的早期版本中并不被支持。例如,如果在hello.fo程序的第(10)行后加入代碼:
<fo:block font-size=\"18pt\" font-family=\"mysimsun\" line-height=\"24pt\" text- align=\"center\"padding-top=\"3pt\">這是宋體</fo:block>
<fo:block font-size=\"18pt\" font-family=\"mysimkai\" line-height=\"24pt\" text- align=\"center\" padding-top=\"3pt\">這是楷體</block>
當再次按照如上步驟運行的時候會出現error提示,這是因為中文字體尚未定義。最早嘗試對FOP打補丁以解決顯示東方字符的是日本人,他們在sourceforge上建立了一個jpfop項目來解決日文字符的顯示問題,當前的FOP版本已經能很好的解決中文顯示的問題,不再需要打補丁,使用相同的方法也顯示中文字符。下面是在FOP中使用中文的步驟:
4.1 建立font metrics文檔的TrueType字體文檔
1) 對于后綴為.ttf的文檔,可以執行以下命令來產生楷體的font metrics文檔:
>java org.apache.fop.fonts.apps.TTFReader C:\\WINDOWS\\Fonts\\simkai.ttf simkai.xml(如果是WIN 2000系統,則路徑名改為“$(系統盤符):\\WINNT\\Fonts\\simkai.ttf”即可)
2) 對于后綴為.ttc的文檔,如果執行
>java org.apache.fop.fonts.apps.TTFReader C:\\WINDOWS\\Fonts\\simsun.ttc simsun.xml
就會產生錯誤的提示信息,輸出如下:
This is a TrueType collection file with2 fonts
Containing the following fonts:
SimSun
NSimSun
java.io.IOException: Failed to read font
at org.apache.fop.fonts.TTFFile.readFont(TTFFile.java:388)
at org.apache.fop.fonts.apps.TTFReader.loadTTF(TTFReader.java:181)
at org.apache.fop.fonts.apps.TTFReader.main(TTFReader.java:143)
后面的異常是由于參數不對造成的,因為后綴為.ttc的TrueType Collection文檔,包含多個TrueType的文檔,所以這時首先要做的是得到這個Collection中所有TrueType的名字,通過以下命令為其中的宋體SimSun.ttc產生font metrics文檔:
>java org.apache.fop.fonts.apps.TTFReader -ttcname \"SimSun\" C:\\WINDOWS\\fonts\\simsun.ttc simsun.xml(-ttcname后面指定需要從.ttc文檔中提取的字體名稱)
4.2 登記上述字體
在FOP主目錄下的conf子目錄下有一個userconfig.xml文檔,為了方便,將它和上一步產生的simsun.xml,simkai.xml都拷貝到演示程序目錄d:\\fop下。并在userconfig.xml的最后幾行<fonts></fonts>標記區中加入以下項:
<font metrics-file=\"simsun.xml\" kerning=\"yes\" embed-file=\"c:\\WINDOWS\\fonts\\simsun.ttc\">
<font-triplet name=\"mysimsun\" style=\"normal\" weight=\"normal\"/>
</font>
<font metrics-file=\"simkai.xml\" kerning=\"yes\" embed-file=\"c:\\WINDOWS\\fonts\\simkai.ttf\">
<font-triplet name=\"mysimkai\" style=\"normal\" weight=\"normal\"/>
</font>
其中metrics-file里可以設相對路徑或絕對路徑(因為本例在同一目錄下,所以只需寫文檔名即可),font-triplet里的name可以自己自由設定,并不要求與字體名一樣。設定這個名字后,在FO里就只能通過這個名字引用這個字體。
4.3 簡單調用FOP
FOP提供的所有對外調用接口都在org.apache.fop.apps下,Driver.class是在這里要討論的程序接口。下面這個程序演示了FOP的顯示中文最常用的使用方式:
1) //foptest.java
2) import java.io.*;
3) import org.xml.sax.InputSource;
4) import org.xml.sax.XMLReader;
5) import org.apache.fop.apps.*;
6) public class foptest
7) {public static void main(String[] args)
8) {try {Driver driver = new Driver();
9) driver.setInputSource(new InputSource (args[0]));
10) driver.setOutputStream(new FileOutputStream(args[1]));
11) driver.setRenderer(Driver.RENDER_PDF);//讀入配置
12) Options options = new Options(new File(\"userconfig.xml\"));
13) driver.run();}
14) catch(Exception e){e.printStackTrace();}
15) }
16) }
用記事本保存為擴展名為.java的文檔并保存到d:\\fop下,然后在MSDos中鍵入命令:
>javac foptest.java
>java foptest hello.fo hello.pdf
即可得到可以顯示中文的PDF文檔了d:\\fop\\hello.pdf。
本例中的所有命令如果將.pdf得擴展名改為.txt或者.doc即可得到相對應得記事本文檔和WORD文檔。
5 結束語
隨著XML越來越受歡迎,相信幾年以內XML將成為存儲和分發文檔的標準格式。本文介紹了XSL-FO這種可以用來創建包含格式化信息的XML文檔的專門XML詞匯表,以及字處理器,并詳細的說明了使用Java通過FOP將XML文檔和XML-FO文檔生成PDF的方法步驟。很多軟件公司也正在更新他們的產品以支持XML,它們中的大部分使用專有的XML格式存儲文檔,XML文檔作為內容的存儲格式,將其轉換為PDF等其他格式的文檔具有非常實用的價值。
參考文獻:
[1] Pitts N. XML技術內幕[M].徐曉梅,龔志翔,王曉云,等,譯.北京:機械工業出版社,2002.
[2] Birbeck M. XML高級編程[M].2版.裴劍鋒,高偉,徐繼偉,等,譯.北京:機械工業出版社,2002.
[3] XSL規范化標準[EB/OL].http://www.w3.org/TR/xsl/Overview. html.
[4] XP下JDK1.4安裝與環境配置完全圖解[EB/OL].http://www.chinaitlab.com/www/news/ article_show.asp?id=29028.
[5] XSL-FO學習筆記[EB/OL].http://www.sentom.net/list.asp?id=63,http://www.sentom.net/list.asp?id=64.
[6] 在程序中嵌入FOP[EB/OL].http://www-128.ibm.com/developerworks/ cn/xml/x-fop/index.html.