使用Java实现HTML转内存PDF时ITextRenderer+Jsoup抛出SAX解析异常如何解决
问题根因
ITextRenderer(即Flying Saucer PDF渲染组件)仅支持解析语法严格符合XML规范的XHTML内容,无法直接处理松散语法的普通HTML,你当前的代码存在核心问题触发SAX解析异常:
- 手动将Jsoup输出语法设置为
Syntax.html,输出内容存在标签未闭合、属性未加引号等不符合XML规范的写法 - 未给HTML根元素声明XHTML必需的命名空间,解析器无法识别文档结构
- 部分场景下输出内容开头会携带多余空白、BOM头,和报错信息中「根元素前的标记格式不合法」的描述完全匹配
修复代码
不需要更换HTML转PDF类库,调整Jsoup的输出配置,生成标准合规的XHTML再传入渲染器即可,修正后的实现如下:
import org.jsoup.nodes.Document; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; import org.xhtmlrenderer.pdf.ITextRenderer; // 解析原始HTML模板 Document document = Jsoup.parse(template, "UTF-8"); // 配置Jsoup输出为XHTML(XML语法)格式 document.outputSettings() .syntax(Document.OutputSettings.Syntax.xml) .charset(StandardCharsets.UTF_8) .outline(true) .indentAmount(2); // 给根标签添加XHTML必须的命名空间,避免样式渲染异常 document.selectFirst("html").attr("xmlns", "http://www.w3.org/1999/xhtml"); ByteArrayOutputStream binaryOutput = new ByteArrayOutputStream(); ITextRenderer renderer = new ITextRenderer(); renderer.setDocumentFromString(document.html()); renderer.layout(); renderer.createPDF(binaryOutput); // binaryOutput中即为内存中生成的PDF文件字节,可直接用于后续存储、返回响应等操作
避坑说明
- 不要在传入渲染器的内容开头手动添加XML声明头(如
<?xml version="1.0" encoding="UTF-8"?>),部分版本的ITextRenderer解析该头部时会直接触发位置1的格式错误 - 若模板使用了HTML5新增标签(如
<section>、<article>),请使用9.1.22及以上版本的Flying Saucer依赖,老版本对HTML5标签兼容性极差,会出现解析失败、样式错乱问题 - 切换到XML输出语法后,Jsoup会自动补全所有未闭合的标签,不需要手动修改原始HTML模板的写法
- 该方案仅对CSS2.1及部分简单CSS3属性支持较好,若需要渲染复杂的现代页面(含大量CSS3、JS动态内容),建议选择基于无头浏览器的渲染方案实现。
内容的提问来源于stack exchange,提问作者Uday Solanki
相关产品推荐
相关产品推荐

