做pdf转换是很实用的工作。已然存在的的转换工具就有很多,其中包括一些成熟的商业软件。而作为java程序开发,我们将借助一个叫FOP的开源工具。
在开始转换之前,我们不得不认识先一下FOP并对它的使用做简单的了解。
FOP (Formatting Objects Processor) 是第一个基于XSL:FO的打印格式处理器,也是第一个与输出无关的格式处理器。它是一个Java程序,能够从对象树中读入然后生成渲染过的页面输出到指定的流。目前支持的输出格式有PDF,PCL,PS,SVG,XML(以树形结构表示),打印机,AWT,MIF和TXT。最主要的输出指的是PDF。
James Tauber - FOP 的最初作者。他开发了该工具的原始版本,而且很大方地开放了该代码,后来又将它移交给 Apache XML Project。(他还给该工具选了一个极好的名称;除了该名称是字首组合词之外,Webster 对 fop 的定义是“过分讲究外表的人”。)现在 James 是 Bowstreet 的首席 XML 设计师。Apache XML项目以开放与合作的方式开发的,提供商业品质的基于XML标准的解决方案。从标准的实施角度看,它能给标准机构(比如IETF和W
3C
)提供反馈信息。
FOP主页 http://xml.apache.org/fop/
FOP使用方式
FOP有3种使用方式,分别为命令行,程序嵌入,XT 嵌入。这里将主要介绍如何在程序中嵌入FOP功能。将XML文件转换为PDF实际上分为2步,第1步是利用XSLT将XML转换为XSL-FO,第2步是将XSL-FO转换为PDF。这里只讲述如何进行第2步的转换编程。
下载fop包后,你需要在CLASSPATH中添加下述jar文件:
{FOP安装目录}/build/fop.jar
{FOP安装目录}/lib/batik.jar
{FOP安装目录}/lib/xalan- 2.0.0 .jar
{FOP安装目录}/lib/xerces- 1.2.3 .jar
{FOP安装目录}/lib/avalon-framework-4.0.jar
{FOP安装目录}/lib/logkit-1.0b4.jar
{FOP安装目录}/lib/jimi-1.0.jar
我是使用Eclipse,只需要在工程属性->构建路径中加入他们,就可以使用这个伟大的工具了。
下面是具体的程序:
这是一个xml文件 test.xml:
<FeatureSRS title="SRS">
<introduction>
<objective>objective here</objective>
<scope>scope here</scope>
<responsibilities>responsibilities here</responsibilities>
<references>reference here</references>
<DAA>
<term>
term here
</term>
<definition>
definition here
</definition>
</DAA>
</introduction>
<generalDescription>
<featureName>
<summary>summary here</summary>
<breakdown>breakdown here</breakdown>
</featureName>
<requirement>
<content>
content here.
</content>
</requirement>
<requirement>
<content>
content2 here.
</content>
</requirement>
<featureInteractions>featureInteractions here</featureInteractions>
</generalDescription>
<strResources>
<strResource>
<estring>
estring here
</estring>
<resourceid>
resourceid here
</resourceid>
<rqmt>
rqmt here.
</rqmt>
</strResource>
</strResources>
</FeatureSRS>
这是它的xsl文件 test.xsl:
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" exclude-result-prefixes="fo">
<xsl:output method="xml" version="1.0" omit-xml-declaration="no" indent="yes"/>
<!-- ========================= -->
<!-- root element: projectteam -->
<!-- ========================= -->
<xsl:template match="FeatureSRS">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simpleA4" page-height=" 29.7cm " page-width=" 21cm " margin-top=" 2cm " margin-bottom=" 2cm " margin-left=" 2cm " margin-right=" 2cm ">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simpleA4">
<fo:flow flow-name="xsl-region-body">
<fo:block font-size=" 20pt " font-weight="bold" space-after=" 5mm " text-align="center">Cardiac Feature SRS
</fo:block>
<fo:block font-size=" 10pt ">
<xsl:apply-templates/>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<!-- ========================= -->
<!-- child element: member -->
<!-- ========================= -->
<xsl:template name="introduction" match="introduction">
<fo:block font-size=" 18pt " font-weight="bold" space-after=" 5mm ">1. Intruction</fo:block>
<fo:block font-size=" 14pt " font-weight="bold" space-after=" 5mm " margin-left=" 5mm ">1.1 Objective</fo:block>
<fo:block font-size=" 10pt " font-weight="normal" space-after=" 5mm " margin-left=" 7mm ">
<xsl:value-of select="objective"/>
</fo:block>
<fo:block font-size=" 14pt " font-weight="bold" space-after=" 5mm " margin-left=" 5mm ">1.2 Scope</fo:block>
<fo:block font-size=" 10pt " font-weight="normal" space-after=" 5mm " margin-left=" 7mm ">
<xsl:value-of select="scope"/>
</fo:block>
<fo:block font-size=" 14pt " font-weight="bold" space-after=" 5mm " margin-left=" 5mm ">1.3. Responsibilities</fo:block>
<fo:block font-size=" 10pt " font-weight="normal" space-after=" 5mm " margin-left=" 7mm ">
<xsl:value-of select="responsibilities"/>
</fo:block>
<fo:block font-size=" 14pt " font-weight="bold" space-after=" 5mm " margin-left=" 5mm ">1.4. References</fo:block>
<fo:block font-size=" 10pt " font-weight="normal" space-after=" 5mm " margin-left=" 7mm ">
<xsl:value-of select="references"/>
</fo:block>
<fo:block font-size=" 14pt " font-weight="bold" space-after=" 5mm " margin-left=" 5mm ">1.5. Definitions, Acronyms, and Abbreviations</fo:block>
<fo:block font-size=" 10pt " font-weight="bold" space-after=" 5mm " margin-left=" 5mm ">
<fo:table table-layout="fixed" border=" 2cm " background-color="#fff2d9" >
<fo:table-column column-width=" 4cm "/>
<fo:table-column column-width=" 6cm "/>
<fo:table-body>
<fo:table-row border="2">
<fo:table-cell>
<fo:block>
<xsl:text>Term</xsl:text>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:text>Definition</xsl:text>
</fo:block>
</fo:table-cell>
</fo:table-row>
<xsl:for-each select="DAA">
<fo:table-row border="2">
<fo:table-cell>
<fo:block>
<xsl:value-of select="term"/>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:value-of select="definition"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:block>
</xsl:template>
<xsl:template name="generalDescription" match="generalDescription">
<fo:block font-size=" 18pt " font-weight="bold" space-after=" 5mm ">2. General Description</fo:block>
<fo:block font-size=" 14pt " font-weight="bold" space-after=" 5mm " margin-left=" 5mm ">2.1. Feature Name</fo:block>
<fo:block font-size=" 14pt " font-weight="bold" space-after=" 5mm " margin-left=" 7mm "> 2.1.1 . Feature Summary</fo:block>
<fo:block font-size=" 10pt " font-weight="normal" space-after=" 5mm " margin-left=" 9mm ">
<xsl:value-of select="featureName/summary"/>
</fo:block>
<fo:block font-size=" 14pt " font-weight="bold" space-after=" 5mm " margin-left=" 7mm "> 2.1.2 . Feature Breakdown</fo:block>
<fo:block font-size=" 10pt " font-weight="normal" space-after=" 5mm " margin-left=" 9mm ">
<xsl:value-of select="featureName/breakdown"/>
</fo:block>
<fo:block font-size=" 14pt " font-weight="bold" space-after=" 5mm " margin-left=" 5mm ">2.2. Feature Requirements</fo:block>
<fo:block font-size=" 10pt " font-weight="normal" space-after=" 5mm " margin-left=" 7mm ">
<xsl:for-each select="requirement">
<xsl:value-of select="content"/>
</xsl:for-each>
</fo:block>
<fo:block font-size=" 14pt " font-weight="bold" space-after=" 5mm " margin-left=" 5mm ">2.3. Feature Interactions</fo:block>
<fo:block font-size=" 10pt " font-weight="normal" space-after=" 5mm " margin-left=" 7mm ">
<xsl:value-of select="featureInteractions"/>
</fo:block>
</xsl:template>
<xsl:template name="strResources" match="strResources">
<fo:block font-size=" 18pt " font-weight="bold" space-after=" 5mm ">3. String Resources </fo:block>
<fo:block font-size=" 10pt " font-weight="bold" space-after=" 5mm " margin-left=" 5mm ">
<fo:table table-layout="fixed" border=" 2cm " background-color="#fff2d9" >
<fo:table-column column-width=" 4cm "/>
<fo:table-column column-width=" 10cm "/>
<fo:table-column column-width=" 4cm "/>
<fo:table-body>
<fo:table-row border="2">
<fo:table-cell>
<fo:block>
<xsl:text>English String</xsl:text>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:text>Resource ID</xsl:text>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:text>Rqmt</xsl:text>
</fo:block>
</fo:table-cell>
</fo:table-row>
<xsl:for-each select="strResource">
<fo:table-row border="2">
<fo:table-cell>
<fo:block>
<xsl:value-of select="estring"/>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:value-of select="resourceid"/>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:value-of select="rqmt"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:block>
</xsl:template>
</xsl:stylesheet>
注意,以上文件不要加:<?xml version="1.0" encoding="UTF-8"?> 这句。
转换的java代码 ExampleXML2PDF.java:
package src;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.avalon.framework.ExceptionUtil;
import org.apache.avalon.framework.logger.ConsoleLogger;
import org.apache.fop.apps.Driver;
import org.apache.fop.messaging.MessageHandler;
public class ExampleXML2PDF{
public void convertXML2PDF(File xml, File xslt, File pdf)
throws TransformerException, IOException {
Driver driver = new Driver();
ConsoleLogger logger = new ConsoleLogger(ConsoleLogger.LEVEL_INFO);
driver.setLogger((org.apache.avalon.framework.logger.Logger) logger);
MessageHandler.setScreenLogger((org.apache.avalon.framework.logger.Logger) logger);
//Setup Renderer (output format)
driver.setRenderer(Driver.RENDER_PDF);
//Setup output
OutputStream out = new java.io.FileOutputStream(pdf);
try {
driver.setOutputStream(out);
//Setup XSLT
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(xslt));
//Setup input for XSLT transformation
Source src = new StreamSource(xml);
//Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(driver.getContentHandler());
//Start XSLT transformation and FOP processing
transformer.transform(src, res);
} finally {
out.close();
}
}
public static void main(String[] args) {
try {
System.out.println("FOP ExampleXML2PDF/n");
System.out.println("Preparing...");
//Setup directories
File baseDir = new File(".");
File outDir = new File(baseDir, "out");
outDir.mkdirs();
File xmlfile = new File("f://tomcat5//webapps//myxml//xmldata//test.xml");
File xsltfile = new File("f://tomcat5//webapps//myxml//xmldata//test.xsl");
File pdffile = new File("f://tomcat5//webapps//myxml//xmldata//test.pdf");
System.out.println("Input: XML (" + xmlfile + ")");
System.out.println("Stylesheet: " + xsltfile);
System.out.println("Output: PDF (" + pdffile + ")");
System.out.println();
System.out.println("Transforming...");
ExampleXML2PDF app = new ExampleXML2PDF();
app.convertXML2PDF(xmlfile, xsltfile, pdffile);
System.out.println("Success!");
} catch (Exception e) {
System.err.println(ExceptionUtil.printStackTrace(e));
System.exit(-1);
}
}
}
编译执行即可。