将Java渲染XML文档为PDF。

3
我有一个XML文档,目前存储在内存中的字符串中,并希望将其呈现为PDF。换句话说,PDF内容将是一个XML文档。该方法呈现的XML是通用的--可能会发送多种类型的XML文档。
我在使用各种基于Java的框架时遇到了一些困难。
Apache FOP
看起来这个框架需要将文档中的XML元素转换为FOP实体。由于所需方法必须接受通用XML,我认为这个框架不符合我的要求。
iText
我尝试使用iText/Flying Saucer (org.xhtmlrenderer)的组合来呈现文档,虽然它确实呈现了PDF,但内容仅包含以空格分隔的数据值,没有XML元素或属性。使用以下代码和测试数据:
文件
<?xml version="1.0" encoding="UTF-8"?>
<root>
  <elem1>value1</elem1>
  <elem2>value2</elem2>
</root>

代码

File inputFile = new File(PdfGenerator.class.getResource("test.xml").getFile());
OutputStream os = new FileOutputStream("c:\\temp\\Sample.pdf");
ITextRenderer renderer = new ITextRenderer();
renderer.setDocument(inputFile);
renderer.layout();
renderer.createPDF(os);
os.close();  

生成一个包含内容值 value1 value2 的 PDF,但不包含标签。

我的问题是:是否有人能够提供一个代码片段,使用以上框架之一来呈现包含 XML 内容的 PDF,或者是否有另一个更适合我的需求的框架?

编辑:我意识到同样的问题在这里被问到了,但似乎所提供的解决方案需要对传入的 XML 文档结构在 CSS 文件中进行深入了解。


你考虑过使用XML输入源的JasperReports吗? - mkl
如果XML像你所说的那样通用,你希望它如何呈现?作为表示XML内容的结构化树形结构? - mkl
3个回答

3

为了举例说明使用fop - 这里就给你了。为了让每个人都能够跟进,我使用了fop命令行工具。

同样的事情也可以在Java代码中轻松完成,这样您就不需要将xml作为文件保存在任何时候。

生成PDF的XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">

<xsl:template match="/">
<fo:root>
  <fo:layout-master-set>
    <fo:simple-page-master master-name="content"
        page-width="210mm" page-height="297mm" margin="20mm 20mm 20mm 20mm">
      <fo:region-body/>
    </fo:simple-page-master>
  </fo:layout-master-set>
  <fo:page-sequence master-reference="content">
    <fo:flow flow-name="xsl-region-body">
      <fo:block>
        <xsl:apply-templates />
    </fo:block>
    </fo:flow>
  </fo:page-sequence>
</fo:root>
</xsl:template>

<xsl:template match="@*">
  <xsl:text> </xsl:text>
  <xsl:value-of select="name()" />
  <xsl:text>="</xsl:text>
    <xsl:value-of select="." />
  <xsl:text>"</xsl:text>
</xsl:template>

<xsl:template match="*">
  <xsl:param name="indent">0</xsl:param>
  <fo:block margin-left="{$indent}">
    <xsl:text>&lt;</xsl:text>
    <xsl:value-of select="name()" />
    <xsl:apply-templates select="@*" />
    <xsl:text>&gt;</xsl:text>
    <xsl:apply-templates>
      <xsl:with-param name="indent" select="$indent+10" />
    </xsl:apply-templates>
    <xsl:text>&lt;/</xsl:text>
    <xsl:value-of select="name()" />
    <xsl:text>&gt;</xsl:text>
  </fo:block>
</xsl:template>

</xsl:stylesheet>

我们称这个文件为xml2pdf.xsl。
代码简述:
  • 模板match="/"主要构建pdf,除了调用其他模板match方法或更精确地说是模板match="*"的行。

  • 模板match=""写入元素的开始和结束,并调用,后者又针对元素中的每个属性(如果有)调用模板match="@"。最后,它调用

  • indent参数通过with-param语句中的select="$indent+10"属性在每个级别上增加10。

使用代码:
# fop -xsl xml2pdf.xsl -xml sample.xml -pdf result.pdf

2

这是使用itext的解决方案。您的html内容在请求中。而且itext是需要付费的,请查看它的许可要求,因为近年来已经有所变化,尽管并不是非常昂贵。

public class MyPDFGeneratorService {

    public byte[] generatePdf(final XhtmlPDFGenerationRequest request) {
        try {

            ITextRenderer renderer = new ITextRenderer();
            renderer.setDocument(this.getDocument(request.getContent()), null);
            renderer.layout();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            renderer.createPDF(baos);
            return this.toByteArray(baos);

        }
        catch (Exception e) {
            throw new PDFGenerationException(
                    "Unable to generate  PDF.", e);
        }
    }

    private Document getDocument(final String content) {
        InputSource is = new InputSource(new BufferedReader(new StringReader(
                content)));
        return XMLResource.load(is).getDocument();
    }


    private byte[] toByteArray(final ByteArrayOutputStream baos)
        throws IOException {
    byte[] bytes = baos.toByteArray();
    baos.close();
    return bytes;

 }

}

2

问题的关键是如何使用这样的框架将任何作为PDF的原始XML文档呈现出来。我知道如何根据已知数据格式手动构建PDF文档...我正在寻找像我提供的代码片段一样简单的东西,可以呈现原始XML(如果这样的东西存在)。 - Javaddict
抱歉有点迟钝...您能解释一下什么是预格式化块吗?您是指对传入的XML字符串应用某种格式,还是向PDF文档添加某种预格式化数据类型? - Javaddict
请使用类似于“Courier”的等宽字体。 - gaborsch
自从5版本以后,iText已经采用AGPL协议,因此我们中的许多人不能再使用它了! - To Kra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接