XML文件如何转换为PDF Java使用Flying Saucer转换XML

3次阅读

xmlpdf必须先用xslt转换为合法xhtml,再由flying saucer渲染;需显式注册中文字体、设置utf-8编码、正确传入baseurl,并避免触发布局bug的css。

XML文件如何转换为PDF Java使用Flying Saucer转换XML

XML转PDF必须先转成XHTML,Flying Saucer不直接解析任意XML

Flying Saucer(即 core-renderer)本质是 XHTML/CSS 渲染引擎,它根本不认识纯 XML 的结构或语义。如果你直接把一个带自定义标签的 book.xml 丢给它,会立刻报 org.xhtmlrenderer.util.XRRuntimeException: Failed to load document 或更模糊的解析失败——因为它默认按 XHTML DTD 去校验,而你的 XML 没有 根、没有 、甚至可能连命名空间都没声明。

所以真实路径只有一条:XML →(XSLT 转换)→ XHTML →(Flying Saucer 渲染)→ PDF。

  • 必须写 XSLT(哪怕只有 5 行),把原始 XML 元素映射为合法 XHTML 标签,比如 <title></title><h1></h1><para></para><p></p>
  • XSLT 文件里要显式声明 xmlns="http://www.w3.org/1999/xhtml",否则 Flying Saucer 仍会拒绝渲染
  • 别试图用 dom 手动拼 HTML 字符串再喂给 ITextRenderer —— 编码、实体转义、DOCTYPE 声明漏一处就白忙

ITextRenderer 渲染前,必须设置字体和编码,否则中文全变方块

Flying Saucer 默认不嵌入中文字体,也不识别 XML 声明里的 encoding="UTF-8"。即使 XSLT 输出了正确的 UTF-8 XHTML,PDF 里中文照样是空心方框或问号。

  • 必须调用 renderer.getFontResolver().addFont("simhei.ttf", "SimHei", true) 显式注册中文字体文件(注意路径要是绝对路径或 classpath 资源)
  • 必须在 XHTML 的 里加 <meta charset="UTF-8">,且确保 XSLT 输出时该 meta 标签真实存在
  • 如果用 ITextRenderer.setDocumentFromString(),传入的字符串必须是 UTF-8 编码的 byte[],不能是 String 直接 toString() 后塞进去

ITextRenderersetDocument()setDocumentFromString() 行为差异很大

这两个方法看着像只是输入方式不同,但底层处理逻辑完全不同:前者走 SAX 解析器,后者走 DOM 构建。对同一份 XHTML,结果可能一个成功一个崩溃。

立即学习Java免费学习笔记(深入)”;

  • setDocument(new File("output.xhtml")):要求文件物理存在,且路径可读;若 XHTML 里有相对 CSS 路径(如 href="style.css"),Flying Saucer 会从该 XHTML 所在目录去加载
  • setDocumentFromString(htmlContent, baseUrl)baseUrl 参数不是可选的!必须传一个以 file:///classpath:/ 开头的有效 base URL,否则 CSS、图片路径全失效
  • 如果 XHTML 里用了 <base href="...">,它会被忽略——Flying Saucer 只认构造时传入的 baseUrl

生成 PDF 时内存溢出或空白页,大概率是 CSS 触发了 Flying Saucer 的布局 bug

某些看似无害的 CSS 会让 Flying Saucer 在分页计算阶段死循环或 OOM,尤其涉及 position: absolutedisplay: table-cell 或未闭合的 @media print 块。

  • 先用浏览器打开生成的 XHTML,确认它能正常显示且没报 CSS 解析错误
  • 临时删掉所有自定义 CSS,只留最简样式(如 body { font-size: 12px; }),看 PDF 是否能出来;能出来就逐段加回 CSS 定位问题
  • 避免在 XHTML 中使用 <style>@page { size: A4; margin: 1cm; }</style> —— Flying Saucer 对 @page 支持极弱,应改用 java 侧调用 renderer.setPageSize(PageSize.A4)

真正卡住的地方往往不是 XML 结构,而是 XSLT 输出的 XHTML 是否“足够像浏览器能吃的 HTML”,以及 CSS 是否触发了 Flying Saucer 那些年久失修的渲染分支。

text=ZqhQzanResources