在开发基于JSP的Web应用时,经常需要根据用户的操作生成PDF文档。尽管有许多教程介绍了如何导出Excel或Word文档,但本文将介绍如何使用XSL Formatting Objects (XSLFO) 和 Apache Formatting Objects Processor (FOP) 来创建PDF文档。
XSLFO是一种用于格式化XML数据的标记语言。它允许开发者定义文档的布局和样式。而Apache FOP是一个Java应用程序,可以将格式化对象树渲染成指定的输出格式,如PDF。
首先有一个包含数据的XML文件,然后使用XSLT将这个XML文件转换成包含格式化对象的XML。这个结果XML被反序列化为Java对象,FOP使用这些Java对象创建PDF文件。
以下是一个简单的XML示例,其中包含了一个人的名字以及他的朋友们的联系信息。
<?xml version="1.0" encoding="iso-8859-1"?>
<root>
<name>shyam</name>
<friend>
<name>Abc</name>
<phNo>90909090909</phNo>
</friend>
<friend>
<name>Xyz</name>
<phNo>32323232323</phNo>
</friend>
</root>
将上述XML保存为Hello.xml。
接下来是一个XSLFO样式表的示例,它首先从上面的XML中获取名字,然后渲染一个包含朋友详细信息的表格。
<?xml version="1.0" encoding="iso-8859-1"?>
<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:template match="root">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="my-page">
<fo:region-body margin="1in"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="my-page">
<fo:flow flow-name="xsl-region-body">
<fo:block>
Hello,
<xsl:value-of select="name"/>!
</fo:block>
<fo:block>
<fo:table>
<fo:table-body>
<fo:table-row>
<fo:table-cell border="solid 1px black" text-align="center" font-weight="bold">
<fo:block>No.</fo:block>
</fo:table-cell>
<fo:table-cell border="solid 1px black" text-align="center" font-weight="bold">
<fo:block>Name</fo:block>
</fo:table-cell>
<fo:table-cell border="solid 1px black" text-align="center" font-weight="bold">
<fo:block>Phone Number</fo:block>
</fo:table-cell>
</fo:table-row>
<xsl:for-each select="./friend">
<fo:table-row>
<fo:table-cell border="solid 1px black" text-align="center">
<fo:block>
<xsl:value-of select="position()"/>
</fo:block>
</fo:table-cell>
<fo:table-cell border="solid 1px black" text-align="center">
<fo:block>
<xsl:value-of select="name"/>
</fo:block>
</fo:table-cell>
<fo:table-cell border="solid 1px black" text-align="center">
<fo:block>
<xsl:value-of select="phNo"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
将上述样式表保存为HelloWorld.xsl。
以下是生成PDF的Java代码示例。
import java.io.File;
import javax.xml.transform.stream.StreamSource;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
import java.io.ByteArrayOutputStream;
import javax.xml.transform.Transformer;
import javax.xml.transform.Result;
public class PDFGenerator {
public static void main(String[] args) {
try {
File xsltfile = new File("HelloWorld.xsl");
StreamSource source = new StreamSource(new File("Hello.xml"));
StreamSource transformSource = new StreamSource(xsltfile);
FopFactory fopFactory = FopFactory.newInstance();
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
Transformer xslfoTransformer = getTransformer(transformSource);
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, outStream);
Result res = new SAXResult(fop.getDefaultHandler());
xslfoTransformer.transform(source, res);
byte[] pdfBytes = outStream.toByteArray();
// 此处省略了将PDF字节写入输出流的代码
} catch (Exception e) {
e.printStackTrace();
}
}
private static Transformer getTransformer(StreamSource streamSource) throws TransformerConfigurationException {
net.sf.saxon.TransformerFactoryImpl impl = new net.sf.saxon.TransformerFactoryImpl();
return impl.newTransformer(streamSource);
}
}
在上述代码中,首先读取XSLT样式表和XML数据文件,然后使用TransformerFactory创建一个Transformer对象。接着,使用FOPFactory创建一个Fop对象,该对象负责将格式化对象树渲染成PDF。最后,通过Transformer的transform方法将XML数据和XSLT样式表转换为PDF。