Apache POI 5.2.5生成XLSX文件XML解析错误修复求助
问题:Apache POI 5.2.5生成的XLSX文件在Excel中打开报错,表格对象丢失
问题现象
- 使用Apache POI 5.2.5生成.xlsx文件,将字节数组返回给客户端下载,本地打开时弹出错误提示:
We found a problem with some content in *.xlsx. Do you want us to try to recover it as much as we can - 确认后文件可打开,但表格对象丢失;谷歌表格可正常打开并显示表格边框
- 直接在服务器保存文件也存在该问题,排除客户端因素
错误日志
Mac上打开文件时的recovery log:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <recoveryLog xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> <logFileName>Repair Result to <FILE_NAME>0.xml</logFileName> <summary>Errors were detected in file '<FILE_PATH>.xlsx'</summary> <removedParts summary="Following is a list of removed parts:"> <removedPart>Removed Part: /xl/tables/table1.xml part with XML error. (Table) Xml parsing error Line 2, column 70.</removedPart> </removedParts> </recoveryLog>
生成的/xl/tables/table1.xml内容:
<?xml version="1.0" encoding="UTF-8"?> <table id="1" displayName="Data Table" name="Data_Table" ref="A1:H3" xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"/>
错误原因
Excel的OpenXML规范要求,表格(Table)必须包含<tableColumns>和<tableStyleInfo>核心节点。当前生成的table XML仅包含基础属性,缺少这两个必填结构,导致Excel判定XML无效,进而移除表格对象。谷歌表格对规范的兼容性更宽松,所以能正常识别。
修复方案
修改createTable方法,补充表格的列定义和样式信息,确保生成符合OpenXML规范的表格结构:
修改后的完整createTable方法
private void createTable(XSSFSheet sheet, int startRow, int startCol, CellStyle headerStyle, CellStyle dataStyle, List<DATA_OBJECT> data) { // 创建表头行 Row headerRow = sheet.createRow(startRow); // 替换为实际的表头名称数组 String[] HEADER_NAMES = {"列1", "列2", "列3", "列4", "列5", "列6", "列7", "列8"}; for (int x = 0; x < HEADER_NAMES.length; x++) { createCell(headerRow, startCol + x, HEADER_NAMES[x], headerStyle); } // 创建数据行 for (int i = 0; i < data.size(); i++) { DATA_OBJECT data_object = data.get(i); Row dataRow = sheet.createRow(startRow + i + 1); // 替换为实际的数据填充逻辑 createCell(dataRow, startCol, data_object.getRelevantValue1(), dataStyle); createCell(dataRow, startCol + 1, data_object.getRelevantValue2(), dataStyle); // ... 依次填充所有列 } // 修正endRow计算:原代码误用baseHoldings,改为传入的data列表 int endRow = startRow + data.size(); int endCol = startCol + HEADER_NAMES.length - 1; // 列索引从0开始,需减1 // 设置自动筛选 sheet.setAutoFilter(new CellRangeAddress(startRow, endRow, startCol, endCol)); // 调整列宽 for (int i = startCol; i <= endCol; i++) { sheet.autoSizeColumn(i); sheet.setColumnWidth(i, sheet.getColumnWidth(i) + 1000); } // 创建Excel表格 XSSFTable table = sheet.createTable(null); CTTable cttable = table.getCTTable(); // 设置表格基础属性 cttable.setDisplayName("Data Table"); cttable.setId(1); cttable.setName("Data_Table"); cttable.setRef(new CellRangeAddress(startRow, endRow, startCol, endCol).formatAsString()); // 添加表格列定义(必填) CTTableColumns ctTableColumns = cttable.addNewTableColumns(); ctTableColumns.setCount(HEADER_NAMES.length); // 列数需与实际一致 for (int i = 0; i < HEADER_NAMES.length; i++) { CTTableColumn ctTableColumn = ctTableColumns.addNewTableColumn(); ctTableColumn.setId(i + 1); // ID从1开始递增 ctTableColumn.setName(HEADER_NAMES[i]); } // 添加表格样式信息(必填) CTTableStyleInfo ctTableStyleInfo = cttable.addNewTableStyleInfo(); ctTableStyleInfo.setName("TableStyleMedium2"); // 使用Excel内置样式,可按需替换 ctTableStyleInfo.setShowColumnStripes(false); ctTableStyleInfo.setShowRowStripes(true); ctTableStyleInfo.setShowFirstColumn(false); ctTableStyleInfo.setShowLastColumn(false); }
关键修复点
- 修正
endRow计算错误:原代码误用baseHoldings.size(),改为data.size() - 添加
<tableColumns>节点:定义表格的列ID和名称,数量需与实际列数匹配 - 添加
<tableStyleInfo>节点:指定表格使用的样式,即使使用默认样式也必须声明
修复后生成的table1.xml会包含完整的结构,Excel可以正常识别表格对象,不再弹出错误提示。
内容的提问来源于stack exchange,提问作者Gal Mor
相关产品推荐
相关产品推荐

