如何在Java中使用XML创建PDF?

时间:2008-10-17 15:09:47

标签: java xml pdf xslt itext

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

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

非常感谢任何帮助。提前谢谢!

11 个答案:

答案 0 :(得分:21)

A - 解释

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

我将提供一个简单的演示,我使用 maven 构建工具来收集所需的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

答案 1 :(得分:15)

答案 2 :(得分:6)

您还可以检查apache项目here

答案 3 :(得分:2)

BIRT有一个Eclipse的GUI,允许您从XML,DB,CSV等定义PDF。

答案 4 :(得分:1)

您可能希望查看那些可以将PDF创建作为转换的XSL-FO库。我会尝试找到一个链接。

答案 5 :(得分:1)

答案 6 :(得分:1)

您可以将XSL-Fo应用于XML并使用Java转换器对其进行转换:

File xmlfile = new File(baseDir, xml);
File xsltfile = new File(baseDir, xsl);
File pdffile = new File(outDir, "ResultXMLPDF.pdf");

FopFactory fopFactory = FopFactory.newInstance();
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();

OutputStream out = new java.io.FileOutputStream(pdffile);
out = new java.io.BufferedOutputStream(out);

try
{
    Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);
    // Setup XSLT
    TransformerFactory factory = TransformerFactory.newInstance();
    Transformer transformer = factory.newTransformer(new StreamSource(xsltfile));

    transformer.setParameter("versionParam", "1.0");

    Source src = new StreamSource(xmlfile);

    Result res = new SAXResult(fop.getDefaultHandler());

    transformer.transform(src, res);

} finally {
    out.close();
}

System.out.println("Success!");

答案 7 :(得分:0)

使用JasperReports。您可以从数据库或XML中提取数据。 您可以导出为多种格式:pdf,excel,html等......

答案 8 :(得分:0)

迟到,您可以使用Adobe的设计人员使用可编辑字段创建静态PDF,然后创建匹配的XDP XML文档。

答案 9 :(得分:0)

有两种方法可以做到这一点。

  • 首先,您可以创建一个普通的PDF,当回读时,它不会为您提供原始XML文件的层次结构。这在'Section 9.4.2 Parsing XML'的{​​{1}}中非常精细地解释。

  • 其次,您可以创建一个标记的PDF,其中既包含XML的层次结构,也包含数据。这使您可以回读PDF文件并从中创建XML文件(与原始XML文件完全匹配)。 'iText in Action : Edition 2'的{​​{1}}中也详细讨论了这一概念。

根据您的要求,您可以使用上述任何一种方法。

答案 10 :(得分:0)

XML,CSS,XHTML等包含开放标准的“活生态系统”,而 XSL-FO 是一个独立的标准。

......历史上XSL-FO和XSLT是作为双胞胎兄弟创建的,但只有XSLT仍然是“活标准”,XSL-FO将大量DNA集中在专有(Adobe)标准中......现在已经过时了。 / p>

严格来说,XSL-FO是一种不会发展的“废弃方式”的一部分,它忽略了CSS,即在“活生态系统”中表达布局的“新方式”。

这不是Java问题

this answer关于 CSS-page 与XML或XHTML的使用。