代码之家  ›  专栏  ›  技术社区  ›  lealceldeiro VonC

使用飞碟式PDF渲染将格式错误的HTML转换为PDF

  •  3
  • lealceldeiro VonC  · 技术社区  · 7 年前

    在项目中 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),它可以正确地创建PDF(如果您使用 好 啊 变量它将创建一个文件 sample-file.pdf

    现在,如果我在 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字符串的“无效”部分。

    重要提示:

    • 分配给变量的值 好 啊 html格式 这里只是一个问题的占位符。真正的是 here .
    • 在实际项目中,html字符串是来自用户的输入。是的,他/她必须知道该放什么,但是,当然,他/她可能会在html构造中出错,所以我必须处理这个问题。

    问题

    • 飞碟PDF渲染 / 自动完成 自我清洁 / 或者其他的 ,然后继续创建PDF文件 (首选) .
    • 有没有更好的方法可以用来克服这个问题。
    2 回复  |  直到 7 年前
        1
  •  2
  •   lealceldeiro VonC    6 年前

    HtmlCleaner 库(请参见 maven link )在解析到飞碟库之前清理HTML代码。

    // 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);
    // ....
    
        2
  •  1
  •   VioletGil    7 年前

    最初的想法是通过另一个能够更好地处理html的库来解析您的输入,然后

    https://jsoup.org/

    五分钟的谷歌搜索发现这是一个非常合理的库。甚至还有一个测试实用程序可以尝试将格式错误的输入放入:

    https://try.jsoup.org/