java - 如何在 Java 中从 XML 创建 PDF?

标签 java xml pdf xslt itext

目前,我正在用 Java 创建一个 XML 文件,并通过使用 XSL/XSLT 对其进行转换,将其显示在 JSP 页面中。现在我需要获取该 XML 文件并在 PDF 中显示相同的信息。有没有办法通过使用某种 XSL 文件来做到这一点?

我看过 iText Java-PDF 库,但我找不到任何方法将它与 XML 和样式表一起使用。

任何帮助将不胜感激。提前致谢!

最佳答案

A - 解释

您应该使用 Apache FOP 框架来生成 pdf 输出。只需提供 xml 格式的数据并使用 xsl-fo 文件呈现页面并指定 margin页面布局等参数 在这个 xsl-fo 文件中。

我将提供一个简单的演示,我使用 ma​​ven 构建工具来收集所需的 jar 文件。请注意,在页面末尾,有一个嵌入 pdf 的 svg 图形。我还想证明你可以在 pdf 中嵌入 svg 图形。

B - XML 输入数据示例

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="application/xml"?>
<users-data>
    <header-section>
        <data-type id="019">User Bill Data</data-type>
        <process-date>Thursday December 9 2016 00:04:29</process-date>
    </header-section>
    <user-bill-data>
        <full-name>John Doe</full-name>
        <postal-code>34239</postal-code>
        <national-id>123AD329248</national-id>
        <price>17.84</price>
    </user-bill-data>
    <user-bill-data>
        <full-name>Michael Doe</full-name>
        <postal-code>54823</postal-code>
        <national-id>942KFDSCW322</national-id>
        <price>34.50</price>
    </user-bill-data>
    <user-bill-data>
        <full-name>Jane Brown</full-name>
        <postal-code>66742</postal-code>
        <national-id>ABDD324KKD8</national-id>
        <price>69.36</price>
    </user-bill-data>
</users-data>

C - XSL-FO 模板

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
    <xsl:output encoding="UTF-8" indent="yes" method="xml" standalone="no" omit-xml-declaration="no"/>
    <xsl:template match="users-data">
        <fo:root language="EN">
            <fo:layout-master-set>
                <fo:simple-page-master master-name="A4-portrail" page-height="297mm" page-width="210mm" margin-top="5mm" margin-bottom="5mm" margin-left="5mm" margin-right="5mm">
                    <fo:region-body margin-top="25mm" margin-bottom="20mm"/>
                    <fo:region-before region-name="xsl-region-before" extent="25mm" display-align="before" precedence="true"/>
                </fo:simple-page-master>
            </fo:layout-master-set>
            <fo:page-sequence master-reference="A4-portrail">
                <fo:static-content flow-name="xsl-region-before">
                    <fo:table table-layout="fixed" width="100%" font-size="10pt" border-color="black" border-width="0.4mm" border-style="solid">
                        <fo:table-column column-width="proportional-column-width(20)"/>
                        <fo:table-column column-width="proportional-column-width(45)"/>
                        <fo:table-column column-width="proportional-column-width(20)"/>
                        <fo:table-body>
                            <fo:table-row>
                                <fo:table-cell text-align="left" display-align="center" padding-left="2mm">
                                    <fo:block>
                                        Bill Id:<xsl:value-of select="header-section/data-type/@id"/>
                                        , Date: <xsl:value-of select="header-section/process-date"/>
                                    </fo:block>
                                </fo:table-cell>
                                <fo:table-cell text-align="center" display-align="center">
                                    <fo:block font-size="150%">
                                        <fo:basic-link external-destination="http://www.example.com">XXX COMPANY</fo:basic-link>
                                    </fo:block>
                                    <fo:block space-before="3mm"/>
                                </fo:table-cell>
                                <fo:table-cell text-align="right" display-align="center" padding-right="2mm">
                                    <fo:block>
                                        <xsl:value-of select="data-type"/>
                                    </fo:block>
                                    <fo:block display-align="before" space-before="6mm">Page <fo:page-number/> of <fo:page-number-citation ref-id="end-of-document"/>
                                    </fo:block>
                                </fo:table-cell>
                            </fo:table-row>
                        </fo:table-body>
                    </fo:table>
                </fo:static-content>
                <fo:flow flow-name="xsl-region-body" border-collapse="collapse" reference-orientation="0">
                    <fo:block>MONTHLY BILL REPORT</fo:block>
                    <fo:table table-layout="fixed" width="100%" font-size="10pt" border-color="black" border-width="0.35mm" border-style="solid" text-align="center" display-align="center" space-after="5mm">
                        <fo:table-column column-width="proportional-column-width(20)"/>
                        <fo:table-column column-width="proportional-column-width(30)"/>
                        <fo:table-column column-width="proportional-column-width(25)"/>
                        <fo:table-column column-width="proportional-column-width(50)"/>
                        <fo:table-body font-size="95%">
                            <fo:table-row height="8mm">
                                <fo:table-cell>
                                    <fo:block>Full Name</fo:block>
                                </fo:table-cell>
                                <fo:table-cell>
                                    <fo:block>Postal Code</fo:block>
                                </fo:table-cell>
                                <fo:table-cell>
                                    <fo:block>National ID</fo:block>
                                </fo:table-cell>
                                <fo:table-cell>
                                    <fo:block>Payment</fo:block>
                                </fo:table-cell>
                            </fo:table-row>
                            <xsl:for-each select="user-bill-data">
                                <fo:table-row>
                                    <fo:table-cell>
                                        <fo:block>
                                            <xsl:value-of select="full-name"/>
                                        </fo:block>
                                    </fo:table-cell>
                                    <fo:table-cell>
                                        <fo:block>
                                            <xsl:value-of select="postal-code"/>
                                        </fo:block>
                                    </fo:table-cell>
                                    <fo:table-cell>
                                        <fo:block>
                                            <xsl:value-of select="national-id"/>
                                        </fo:block>
                                    </fo:table-cell>
                                    <fo:table-cell>
                                        <fo:block>
                                            <xsl:value-of select="price"/>
                                        </fo:block>
                                    </fo:table-cell>
                                </fo:table-row>
                            </xsl:for-each>
                        </fo:table-body>
                    </fo:table>
                    <fo:block id="end-of-document">
                        <fo:instream-foreign-object>
                            <svg width="200mm" height="150mm" version="1.1" xmlns="http://www.w3.org/2000/svg">
                                <path d="M153 334
C153 334 151 334 151 334
C151 339 153 344 156 344
C164 344 171 339 171 334
C171 322 164 314 156 314
C142 314 131 322 131 334
C131 350 142 364 156 364
C175 364 191 350 191 334
C191 311 175 294 156 294
C131 294 111 311 111 334
C111 361 131 384 156 384
C186 384 211 361 211 334
C211 300 186 274 156 274" style="fill:yellow;stroke:red;stroke-width:2"/>
                            </svg>
                        </fo:instream-foreign-object>
                    </fo:block>
                </fo:flow>
            </fo:page-sequence>
        </fo:root>
    </xsl:template>
</xsl:stylesheet>

D - 项目目录结构

enter image description here

E - Pom 文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.levent.fopdemo</groupId>
    <artifactId>apache-fop-demo</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>apache-fop-demo</name>
    <url>http://maven.apache.org</url>

    <properties>
        <fop.version>2.1</fop.version>
    </properties>

    <dependencies>      
        <!-- https://mvnrepository.com/artifact/org.apache.xmlgraphics/fop -->
        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>fop</artifactId>
            <version>${fop.version}</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>Apache Fop Demo</finalName>

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

F - 演示代码:PdfGenerationDemo.java

package com.levent.fopdemo;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

import javax.xml.transform.Result;
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.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;

public class PdfGenerationDemo 
{
    public static final String RESOURCES_DIR;
    public static final String OUTPUT_DIR;

    static {
        RESOURCES_DIR = "src//main//resources//";
        OUTPUT_DIR = "src//main//resources//output//";
    }

    public static void main( String[] args )
    {
        try {
            convertToPDF();
        } catch (FOPException | IOException | TransformerException e) {
            e.printStackTrace();
        }
    }

    public static void convertToPDF() throws IOException, FOPException, TransformerException {
        // the XSL FO file
        File xsltFile = new File(RESOURCES_DIR + "//template.xsl");
        // the XML file which provides the input
        StreamSource xmlSource = new StreamSource(new File(RESOURCES_DIR + "//data.xml"));
        // create an instance of fop factory
        FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
        // a user agent is needed for transformation
        FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
        // Setup output
        OutputStream out;
        out = new java.io.FileOutputStream(OUTPUT_DIR + "//output.pdf");

        try {
            // Construct fop with desired output format
            Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);

            // Setup XSLT
            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer transformer = factory.newTransformer(new StreamSource(xsltFile));

            // Resulting SAX events (the generated FO) must be piped through to
            // FOP
            Result res = new SAXResult(fop.getDefaultHandler());

            // Start XSLT transformation and FOP processing
            // That's where the XML is first transformed to XSL-FO and then
            // PDF is created
            transformer.transform(xmlSource, res);
        } finally {
            out.close();
        }
    }
}

G - 样本输出:output.pdf

enter image description here

关于java - 如何在 Java 中从 XML 创建 PDF?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/212577/

相关文章:

java - 如何阅读所有电子邮件?

xml - 解析 xmlToList 中的 CDATA 字段

sql-server - 使用 T-SQL 查询 XML 字段

php - 如何从pdf中提取文本层和背景层?

Java:如何使用 iText 从 PDF 文件中按选定区域提取文本?

java - 为什么数据源在没有数据库 URL 的情况下也能正常工作?

java - map 集合中的多个值作为键

java - 如何在Java + Akka上读取文件并发

C# XML 按键值选择字典节点

java - 来自 mysql 连接的 itextpdf pdf