使用Flying Saucer PDF Rendering将格式不正确的HTML转换为PDF

6
在一个名为GitHub的项目中,我正在尝试将任意的HTML字符串转换为PDF版本。所谓转换是指解析HTML,并将其呈现为PDF文件。
为了实现这一目标,我使用了Flying Saucer PDF Rendering,如下所示:

Main.java

public class Main {

    public static void main(String [] args) {
        final String ok = "<valid html here>: see github rep for real html markup here";
        final String html = "<invalid html here>: see github rep for real html markup here";
        try {
            // final byte[] bytes = generatePDFFrom(ok); // works!
            final byte[] bytes = generatePDFFrom(html); // does NOT work :(
            try(FileOutputStream fos = new FileOutputStream("sample-file.pdf")) {
                fos.write(bytes);
            }

        } catch (IOException | DocumentException e) {
            e.printStackTrace();
        }
    }

    private static byte[] generatePDFFrom(String html) throws IOException, DocumentException {
        final ITextRenderer renderer = new ITextRenderer();
        renderer.setDocumentFromString(html);
        renderer.layout();
        try (ByteArrayOutputStream fos = new ByteArrayOutputStream(html.length())) {
            renderer.createPDF(fos);
            return fos.toByteArray();
        }
    }
}

在上面的代码中,如果我使用存储在ok变量中的HTML字符串(这是一个“有效”的HTML),它将正确地创建PDF文件(如果您使用ok变量运行GitHub项目,则会在项目文件夹中创建一个名为sample-file.pdf的文件,其中包含一些呈现的HTML)。现在,如果我使用html变量中的值(带有无效标签、标签可能未正确关闭等的HTML),它会抛出以下错误(错误可能因不正确的值而异):
ERROR:  'The markup in the document following the root element must be well-formed.'
Exception in thread "main" org.xhtmlrenderer.util.XRRuntimeException: Can't load the XML resource (using TrAX transformer). org.xml.sax.SAXParseException; lineNumber: 22; columnNumber: 9; The markup in the document following the root element must be well-formed.
    at org.xhtmlrenderer.resource.XMLResource$XMLResourceBuilder.transform(XMLResource.java:222)
    at org.xhtmlrenderer.resource.XMLResource$XMLResourceBuilder.createXMLResource(XMLResource.java:181)
    at org.xhtmlrenderer.resource.XMLResource.load(XMLResource.java:84)
    at org.xhtmlrenderer.pdf.ITextRenderer.setDocumentFromString(ITextRenderer.java:171)
    at org.xhtmlrenderer.pdf.ITextRenderer.setDocumentFromString(ITextRenderer.java:166)
    at Main.generatePDFFrom(Main.java:84)
    at Main.main(Main.java:72)
Caused by: javax.xml.transform.TransformerException: org.xml.sax.SAXParseException; lineNumber: 22; columnNumber: 9; The markup in the document following the root element must be well-formed.
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:740)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:343)
    at org.xhtmlrenderer.resource.XMLResource$XMLResourceBuilder.transform(XMLResource.java:220)
    ... 6 more
Caused by: org.xml.sax.SAXParseException; lineNumber: 22; columnNumber: 9; The markup in the document following the root element must be well-formed.
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1239)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transformIdentity(TransformerImpl.java:659)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:728)
    ... 8 more

据我所了解,这是由于HTML字符串中的“无效”部分导致的。

重要提示:

  • 此处分配给变量okhtml的值只是问题的占位符。真正的值在这里
  • 在实际项目中,HTML字符串是来自用户的输入。是的,他/她必须知道该放什么,但是,当然,他/她可能会在HTML格式上犯一些错误,因此我必须处理这个问题。

问题

  • 是否有办法“告诉”Flying Saucer PDF Rendering忽略/自动完成/清理或任何其他无效部分,并继续创建PDF文件(首选)
  • 我是否可以采用更好的方法来克服这个问题。

你必须小心使用的标签。例如:"<br>"。请查看此问题的第二个答案。 - Leandro Roura Sixto
2个回答

5

由于我在使用Flying Saucer从HTML生成PDF时遇到了同样的问题,因此我使用了HtmlCleaner库(请参见Maven链接)来清理HTML代码,并将其解析到Flying Saucer库中。

// Clean the html to use in the flying saucer converting tool
// get the element you want to serialize
HtmlCleaner cleaner = new HtmlCleaner();
TagNode rootTagNode = cleaner.clean(html);
// set up properties for the serializer (optional, see online docs)
CleanerProperties cleanerProperties = cleaner.getProperties();
// use the getAsString method on an XmlSerializer class
XmlSerializer xmlSerializer = new PrettyXmlSerializer(cleanerProperties);
String cleanedHtml = xmlSerializer.getAsString(rootTagNode);

// use the https://github.com/flyingsaucerproject/flyingsaucer to convert cleaned HTML to PDF
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(cleanedHtml);
// ....

1
一个最初的想法是通过另一个能更好地处理html的库来解析您的输入,然后将该库的结果toString()为PDF渲染器。

https://jsoup.org/

我花了五分钟在谷歌上搜索,找到了一个相当不错的库可以使用。甚至有一个测试工具,你可以尝试将格式错误的输入扔进去:

https://try.jsoup.org/


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