当 header 的单元格包含换行符时,Apache POI createTable 生成损坏的文件
Apache POI createTable generates corrupted file when a header's cell contains a line break
我正在使用 Apache POI 4.1.2 在 Java 中创建 Excel 个文件。我有一段代码可以从现有的单元格创建一个 table,并且一切正常,直到我在 header 的单元格中有一个换行符。
之后我尝试更改 table 的列名称,但没有解决任何问题。
下面是重现问题的最短代码:
public void test() throws IOException {
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sheet = wb.createSheet();
// headers
XSSFRow headersRow = sheet.createRow(0);
headersRow.createCell(0).setCellValue("Column1");
headersRow.createCell(1).setCellValue("Column2");
// a second row
XSSFRow row = sheet.createRow(1);
row.createCell(0).setCellValue(1);
row.createCell(1).setCellValue(2);
// create a table
AreaReference area = wb.getCreationHelper().createAreaReference(
new CellReference(sheet.getRow(0).getCell(0)),
new CellReference(sheet.getRow(1).getCell(1))
);
XSSFTable table = sheet.createTable(area);
// styling (no problem here)
sheet.setColumnWidth(0, 5000);
sheet.setColumnWidth(1, 5000);
CTTable cttable = table.getCTTable();
cttable.addNewTableStyleInfo();
XSSFTableStyleInfo style = (XSSFTableStyleInfo) table.getStyle();
style.setName("TableStyleMedium6");
style.setShowColumnStripes(false);
style.setShowRowStripes(true);
cttable.addNewAutoFilter().setRef(area.formatAsString());
CellStyle cellStyle = wb.createCellStyle();
cellStyle.setWrapText(true);
headersRow.getCell(0).setCellStyle(cellStyle);
// this file is OK
try (FileOutputStream outputStream = new FileOutputStream("C:\tmp\test.xlsx")) {
wb.write(outputStream);
}
// add a line break in a header's cell
headersRow.getCell(0).setCellValue("Column1\nwith a line break");
// this file has a problem
try (FileOutputStream outputStream = new FileOutputStream("C:\tmp\test2.xlsx")) {
wb.write(outputStream);
}
// this doesn't fix anything
table.getColumns().get(0).setName("Column1");
try (FileOutputStream outputStream = new FileOutputStream("C:\tmp\test3.xlsx")) {
wb.write(outputStream);
}
// neither does this
cttable.getTableColumns().getTableColumnList().get(0).setName("Column1");
try (FileOutputStream outputStream = new FileOutputStream("C:\tmp\test4.xlsx")) {
wb.write(outputStream);
}
}
Excel 正确加载 text.xlsx,但抱怨所有其他文件:
我们发现某些内容存在问题...
Excel修复文件后,一切正常,但我想去掉警告信息。
如有任何帮助,我们将不胜感激。
谢谢
这是 XSSFTable.updateHeaders 的一个错误。在写入 table 的 XML
时调用此方法。这是因为 table 列名称始终必须与单元格内容同步。例如,如果单元格内容是“Column1”并且此单元格是 table 的列 header,则此 table 的列名称也必须是“Column1”(XML: <tableColumn id="1" name="Column1"/>
).
但是对于 headers 列中的换行,有一个特殊之处。如果单元格内容是“Column1\nwith一个换行符”并且这个单元格是一个table的列header,那么这个table的列名必须是XML 为 <tableColumn id="1" name="Column1_x000a_with a line break"/>
。所以“\n”被替换为“x000a”。此外,“\r”必须替换为“x000d”。这是因为“\r\n”换行不会有XML
.
中换行的意思
所以 XSSFTable.java - updateHeaders 必须这样修补,即“\n”被“x000a”替换,“\r”被“[=30”替换=]x000d".
...
public void updateHeaders() {
XSSFSheet sheet = (XSSFSheet)getParent();
CellReference ref = getStartCellReference();
if (ref == null) return;
int headerRow = ref.getRow();
int firstHeaderColumn = ref.getCol();
XSSFRow row = sheet.getRow(headerRow);
DataFormatter formatter = new DataFormatter();
if (row != null && row.getCTRow().validate()) {
int cellnum = firstHeaderColumn;
CTTableColumns ctTableColumns = getCTTable().getTableColumns();
if(ctTableColumns != null) {
for (CTTableColumn col : ctTableColumns.getTableColumnList()) {
XSSFCell cell = row.getCell(cellnum);
if (cell != null) {
String colName = formatter.formatCellValue(cell);
colName = colName.replace("\n", "_x000a_");
colName = colName.replace("\r", "_x000d_");
col.setName(colName);
}
cellnum++;
}
}
}
tableColumns = null;
columnMap = null;
xmlColumnPrs = null;
commonXPath = null;
}
...
由于 XSSFTable.updateHeaders 被调用而 table 的 XML
在 XSSFWorkbook.write
被写入,因此除了修补此方法之外别无他法。没有任何机会改变 table 的 XML
而 XSSFWorkbook.write
.
我正在使用 Apache POI 4.1.2 在 Java 中创建 Excel 个文件。我有一段代码可以从现有的单元格创建一个 table,并且一切正常,直到我在 header 的单元格中有一个换行符。
之后我尝试更改 table 的列名称,但没有解决任何问题。
下面是重现问题的最短代码:
public void test() throws IOException {
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sheet = wb.createSheet();
// headers
XSSFRow headersRow = sheet.createRow(0);
headersRow.createCell(0).setCellValue("Column1");
headersRow.createCell(1).setCellValue("Column2");
// a second row
XSSFRow row = sheet.createRow(1);
row.createCell(0).setCellValue(1);
row.createCell(1).setCellValue(2);
// create a table
AreaReference area = wb.getCreationHelper().createAreaReference(
new CellReference(sheet.getRow(0).getCell(0)),
new CellReference(sheet.getRow(1).getCell(1))
);
XSSFTable table = sheet.createTable(area);
// styling (no problem here)
sheet.setColumnWidth(0, 5000);
sheet.setColumnWidth(1, 5000);
CTTable cttable = table.getCTTable();
cttable.addNewTableStyleInfo();
XSSFTableStyleInfo style = (XSSFTableStyleInfo) table.getStyle();
style.setName("TableStyleMedium6");
style.setShowColumnStripes(false);
style.setShowRowStripes(true);
cttable.addNewAutoFilter().setRef(area.formatAsString());
CellStyle cellStyle = wb.createCellStyle();
cellStyle.setWrapText(true);
headersRow.getCell(0).setCellStyle(cellStyle);
// this file is OK
try (FileOutputStream outputStream = new FileOutputStream("C:\tmp\test.xlsx")) {
wb.write(outputStream);
}
// add a line break in a header's cell
headersRow.getCell(0).setCellValue("Column1\nwith a line break");
// this file has a problem
try (FileOutputStream outputStream = new FileOutputStream("C:\tmp\test2.xlsx")) {
wb.write(outputStream);
}
// this doesn't fix anything
table.getColumns().get(0).setName("Column1");
try (FileOutputStream outputStream = new FileOutputStream("C:\tmp\test3.xlsx")) {
wb.write(outputStream);
}
// neither does this
cttable.getTableColumns().getTableColumnList().get(0).setName("Column1");
try (FileOutputStream outputStream = new FileOutputStream("C:\tmp\test4.xlsx")) {
wb.write(outputStream);
}
}
Excel 正确加载 text.xlsx,但抱怨所有其他文件:
我们发现某些内容存在问题...
Excel修复文件后,一切正常,但我想去掉警告信息。
如有任何帮助,我们将不胜感激。 谢谢
这是 XSSFTable.updateHeaders 的一个错误。在写入 table 的 XML
时调用此方法。这是因为 table 列名称始终必须与单元格内容同步。例如,如果单元格内容是“Column1”并且此单元格是 table 的列 header,则此 table 的列名称也必须是“Column1”(XML: <tableColumn id="1" name="Column1"/>
).
但是对于 headers 列中的换行,有一个特殊之处。如果单元格内容是“Column1\nwith一个换行符”并且这个单元格是一个table的列header,那么这个table的列名必须是XML 为 <tableColumn id="1" name="Column1_x000a_with a line break"/>
。所以“\n”被替换为“x000a”。此外,“\r”必须替换为“x000d”。这是因为“\r\n”换行不会有XML
.
所以 XSSFTable.java - updateHeaders 必须这样修补,即“\n”被“x000a”替换,“\r”被“[=30”替换=]x000d".
...
public void updateHeaders() {
XSSFSheet sheet = (XSSFSheet)getParent();
CellReference ref = getStartCellReference();
if (ref == null) return;
int headerRow = ref.getRow();
int firstHeaderColumn = ref.getCol();
XSSFRow row = sheet.getRow(headerRow);
DataFormatter formatter = new DataFormatter();
if (row != null && row.getCTRow().validate()) {
int cellnum = firstHeaderColumn;
CTTableColumns ctTableColumns = getCTTable().getTableColumns();
if(ctTableColumns != null) {
for (CTTableColumn col : ctTableColumns.getTableColumnList()) {
XSSFCell cell = row.getCell(cellnum);
if (cell != null) {
String colName = formatter.formatCellValue(cell);
colName = colName.replace("\n", "_x000a_");
colName = colName.replace("\r", "_x000d_");
col.setName(colName);
}
cellnum++;
}
}
}
tableColumns = null;
columnMap = null;
xmlColumnPrs = null;
commonXPath = null;
}
...
由于 XSSFTable.updateHeaders 被调用而 table 的 XML
在 XSSFWorkbook.write
被写入,因此除了修补此方法之外别无他法。没有任何机会改变 table 的 XML
而 XSSFWorkbook.write
.