Apache POI转换含动态表格的Docx为PDF时遇CTTblGrid空指针异常
问题根源
异常fr.opensagres.poi.xwpf.converter.core.XWPFConverterException: java.lang.NullPointerException: Cannot invoke "org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGrid.getGridColList()" because "grid" is null的核心原因是:C#用DocumentFormat.OpenXml动态生成的表格缺失了<w:tblGrid>节点(对应POI中的CTTblGrid对象)。
Apache POI的XWPF PDF转换器要求所有表格必须包含网格定义(TblGrid)来确定列布局,但Word客户端在打开文档时会自动补全这个缺失的结构,所以手动另存后就能正常转换。
解决方案
方案1:在C#生成表格时手动添加TblGrid(最优解)
在创建动态表格的代码中,为每个Table对象添加TableGrid(对应TblGrid),并根据表格列数添加GridCol元素。示例代码:
// 假设已创建Table实例table TableGrid tblGrid = new TableGrid(); // 根据表格实际列数添加GridCol,示例为3列 for (int i = 0; i < 3; i++) { // 设置列宽度,单位为二十分之一磅,可按需调整 tblGrid.AppendChild(new GridCol() { Width = "2000" }); } // 将TableGrid添加到表格中 table.AppendChild(tblGrid);
这样生成的Docx自带完整的表格网格定义,无需依赖Word修复,直接可被Apache POI转换。
方案2:在Java转换前补全缺失的TblGrid
如果无法修改C#的生成逻辑,可以在Java转换流程中,遍历文档所有表格,自动补全缺失的TblGrid结构。示例代码:
import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGrid; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGridCol; import java.math.BigInteger; // 读取输入的Docx字节流 XWPFDocument doc = new XWPFDocument(inputStream); // 遍历所有表格补全TblGrid for (XWPFTable table : doc.getTables()) { CTTbl ctTbl = table.getCTTbl(); if (ctTbl.getTblGrid() == null) { CTTblGrid tblGrid = ctTbl.addNewTblGrid(); // 获取表格列数(简单场景取第一行单元格数,跨行跨列需额外处理) int colCount = table.getRow(0).getTableCells().size(); for (int i = 0; i < colCount; i++) { CTTblGridCol gridCol = tblGrid.addNewGridCol(); // 设置默认列宽度,可根据实际单元格宽度调整 gridCol.setW(BigInteger.valueOf(2000)); } } } // 执行后续PDF转换逻辑 // ...
注意事项
如果表格存在跨行(vMerge)或跨列(gridSpan)的单元格,需要解析单元格属性计算实际网格列数,避免列数统计错误。
内容的提问来源于stack exchange,提问作者Leonard Bernstein
相关产品推荐
相关产品推荐

