65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 XSLFO 和 FOP 进行 PDF 生成

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.70/5 (7投票s)

2009年6月26日

CPOL

2分钟阅读

viewsIcon

182565

一篇关于如何使用 XSLFO 和 FOP 以编程方式创建 PDF 文档的文章。

引言

本文档描述了如何使用 XSLFO 和 Apache FOP 创建 PDF 文档。

背景

在开发基于 JSP 的 Web 应用程序时,我遇到了一个需求,即在单击按钮时创建 PDF 文档并导出它。 有很多教程可用于导出到 Excel、Word 等。我决定使用 XSLFO 和 FOP 来创建 PDF 文档。

XSLFO 是 XSL 格式化对象,可用于格式化 XML 数据。 更多信息请访问 此处此处

Apache FOP(格式化对象处理器)是一个 Java 应用程序,它读取格式化对象树并将生成的页面渲染到指定的输出(此处,在本例中,为 PDF)。 更多信息请访问 此处

工作原理

我们有一个包含数据的 XML,以及一个 XSLT,它通过从第一个 XML 中获取数据来创建包含格式化对象的 XML。 将此生成的 XML 反序列化为 Java 对象。 FOP 使用这些 Java 对象创建 PDF 文件。

Hello World XSLFO

这是一个示例 XML。 此 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>

将其保存为 Hello.xml

这是示例 xslfo 样式表。 首先,它从上面的 XML 中获取一个姓名。 然后,此 xslt 渲染一个包含上述 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

Java 代码

这是创建 PDF 的代码

// the XSL FO file
File xsltfile = new File("HelloWorld.xsl");
// the XML file from which we take the name
StreamSource source = new StreamSource(new File("Hello.xml"));
// creation of transform source
StreamSource transformSource = new StreamSource(xsltfile);
// create an instance of fop factory
FopFactory fopFactory = FopFactory.newInstance();
// a user agent is needed for transformation
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
// to store output
ByteArrayOutputStream outStream = new ByteArrayOutputStream();

Transformer xslfoTransformer;
try
{
	xslfoTransformer = getTransformer(transformSource);
	// Construct fop with desired output format
        Fop fop;
	try
	{
		fop = fopFactory.newFop
			(MimeConstants.MIME_PDF, foUserAgent, outStream);
		// Resulting SAX events (the generated FO) 
		// must be piped through to FOP
                Result res = new SAXResult(fop.getDefaultHandler());

		// Start XSLT transformation and FOP processing
		try
		{
		        // everything will happen here..
			xslfoTransformer.transform(source, res);
			// if you want to get the PDF bytes, use the following code
			//return outStream.toByteArray();

			// if you want to save PDF file use the following code
			/*File pdffile = new File("Result.pdf");
			OutputStream out = new java.io.FileOutputStream(pdffile);
                        out = new java.io.BufferedOutputStream(out);
                        FileOutputStream str = new FileOutputStream(pdffile);
                        str.write(outStream.toByteArray());
                        str.close();
                        out.close();*/

			// to write the content to out put stream
			byte[] pdfBytes = outStream.toByteArray();
                        response.setContentLength(pdfBytes.length);
                        response.setContentType("application/pdf");
                        response.addHeader("Content-Disposition", 
					"attachment;filename=pdffile.pdf");
                        response.getOutputStream().write(pdfBytes);
                        response.getOutputStream().flush();
		}
		catch (TransformerException e) {
			throw e;
		}
	}
	catch (FOPException e) {
		throw e;
	}
}
catch (TransformerConfigurationException e)
{
	throw e;
}
catch (TransformerFactoryConfigurationError e)
{
	throw e;
}

getTransformer”函数。 我使用了 xslt2 处理器来进行高级 XSLT 处理。 简单的 XSLT 处理器在这里就足够了。

private Transformer getTransformer(StreamSource streamSource)
{
	// setup the xslt transformer
	net.sf.saxon.TransformerFactoryImpl impl = 
			new net.sf.saxon.TransformerFactoryImpl();

	try {
		return impl.newTransformer(streamSource);

	} catch (TransformerConfigurationException e) {
		e.printStackTrace();
	}
	return null;
}

以下是上述代码中使用的主要命名空间列表

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;

工作原理

首先发生正常的 XML-XSLT 转换,从而创建 XSLFO XML。 Hello.xml 通过 HelloWorld.xsl 转换创建以下 XML。

<?xml version="1.0" encoding="utf-8"?>
<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, shyam!</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>
            <fo:table-row>
              <fo:table-cell border="solid 1px black" text-align="center">
                <fo:block>1</fo:block>
              </fo:table-cell>
              <fo:table-cell border="solid 1px black" text-align="center">
                <fo:block>Abc</fo:block>
              </fo:table-cell>
              <fo:table-cell border="solid 1px black" text-align="center">
                <fo:block>90909090909</fo:block>
              </fo:table-cell>
            </fo:table-row>
            <fo:table-row>
              <fo:table-cell border="solid 1px black" text-align="center">
                <fo:block>2</fo:block>
              </fo:table-cell>
              <fo:table-cell border="solid 1px black" text-align="center">
                <fo:block>Xyz</fo:block>
              </fo:table-cell>
              <fo:table-cell border="solid 1px black" text-align="center">
                <fo:block>32323232323</fo:block>
              </fo:table-cell>
            </fo:table-row>
          </fo:table-body>
        </fo:table>
      </fo:block>
    </fo:flow>
  </fo:page-sequence>
</fo:root>

此 XML 是序列化的 FO 对象树。 此 XML 被反序列化为 FO 对象,并通过这些对象,FOP 绘制 PDF 文件。 所有这些过程都发生在 transform; 函数中,我们无需担心!!!

关注点

FOP 是一个为我们提供创建 PDF 的绝佳工具。 我希望这段代码能帮助您以编程方式创建 PDF。 谢谢。

历史

  • 初始版本于 2009 年 6 月 24 日
© . All rights reserved.