gpt4 book ai didi

java - 使用 Apache Poi 重命名 XSSFTable 的 header 会导致损坏的 XLSX 文件

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:45:10 29 4
gpt4 key购买 nike

我正在尝试重命名现有 xlsx 文件的标题。这个想法是用一个 excel 文件将数据从 XML 导出到 excel,并在某些用户进行调整后重新导入 XML。

目前,我们已经使用 Excel 创建了一个"template"xlsx 表,其中已经包含一个可排序表(poi 中的 XSSFTable)和一个到 XSD 源的映射。然后我们通过POI将其导入,将XML数据映射到其中并保存。为了根据用户调整工作表,我们希望将现有表格的标题/列名翻译成不同的语言。它适用于 POI 3.10-FINAL,但自从升级到 4.0.1 后,它会在打开时导致损坏的 xlsx 文件。

我已经在 stackoverflow 上找到了这个问题 Excel file gets corrupted when i change the value of any cell in the header (Columns Title)但它没有回答而且很旧。但我试图弄清楚评论可能是关于什么的,并试图展平现有的 XSSFTable,将填充的数据复制到新工作表并将新的 XSSFTable 放在数据上。可悲的是,这似乎非常复杂,所以我又回来纠正损坏的标题单元格。我还尝试使用 POI 创建整个工作表并放弃使用该"template"-xslx,但我无法弄清楚如何实现我们的 XSD 映射(在 Excel 中,其开发人员工具 -> 源代码 -> 添加然后映射动态表中某些单元格的节点)

poi升级之前一直有效的代码基本是这样的:

//Sheet is the current XSSFSheet
//header is a Map with the original header-name from the template mapped to a the new translated name
//headerrownumber is the row containing the tableheader to be translated

public static void translateHeaders(Sheet sheet,final Map<String,String> header,int headerrownumber) {
CellRangeAddress address = new CellRangeAddress(headerrownumber,headerrownumber,0,sheet.getRow(headerrownumber).getLastCellNum()); //Cellrange is the header-row

MyCellWalk cellWalk = new MyCellWalk (sheet,address);
cellWalk.traverse(new CellHandler() {
public void onCell(Cell cell, CellWalkContext ctx) {
String val = cell.getStringCellValue();
if (header.containsKey(val)) {
cell.setCellValue(header.get(val));
}
}
});
}

MyCellWalk 是一个 org.apache.poi.ss.util.cellwalk.CellWalk,它遍历从左上角到右下角的单元格范围。

据我所知,仅仅更改单元格的平面值是不够的,因为 xlsx 在他们的一些 map 中保留了对单元格名称的引用,但我不知道如何获取它们并重命名标题。也许还有另一种翻译标题名称的方法?

最佳答案

嗯,XSSFTable.updateHeaders如果 apache poi 应该可以解决问题不会失败的。

以下所有操作都是使用 apache poi 4.0.1 完成的.

我已经下载了你的dummy_template.xlsx然后尝试更改工作表中的表格列标题。但即使在调用 XSSFTable.updateHeaders 之后XSSFTable 中的列名没有改变。所以我看了一下 XSSFTable.java -> updateHeaders以确定为什么这不会发生。我们发现:

if (row != null && row.getCTRow().validate()) {
//do changing the column names
}

因此,只有当工作表中的相应行有效时,列名才会更改 XML根据 Office Open XML namespace 。但在以后Excel版本(2007 年之后)添加了额外的 namespace 。在本例中,该行的 XML看起来像:

<row r="4" spans="1:3" x14ac:dyDescent="0.25">

注意附加的 x14ac:dyDescent属性。这就是为什么 row.getCTRow().validate()返回 false .

以下代码获取您的 dummy_template.xlsx , 重命名工作表中的列标题,然后调用解除武装的版本 static void updateHeaders(XSSFTable table) .之后 result.xlsx有效于 Excel 开业.

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.ss.util.cellwalk.*;

import org.apache.poi.xssf.usermodel.*;

import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;

import java.io.*;
import java.util.*;

class ExcelRenameTableColumns {

static void translateHeaders(Sheet sheet, final Map<String,String> header, int headerrownumber) {
CellRangeAddress address = new CellRangeAddress(
headerrownumber, headerrownumber,
0, sheet.getRow(headerrownumber).getLastCellNum());

CellWalk cellWalk = new CellWalk (sheet, address);
cellWalk.traverse(new CellHandler() {
public void onCell(Cell cell, CellWalkContext ctx) {
String val = cell.getStringCellValue();
if (header.containsKey(val)) {
cell.setCellValue(header.get(val));
}
}
});
}

static void updateHeaders(XSSFTable table) {
XSSFSheet sheet = (XSSFSheet)table.getParent();
CellReference ref = table.getStartCellReference();

if (ref == null) return;

int headerRow = ref.getRow();
int firstHeaderColumn = ref.getCol();
XSSFRow row = sheet.getRow(headerRow);
DataFormatter formatter = new DataFormatter();

System.out.println(row.getCTRow().validate()); // false!

if (row != null /*&& row.getCTRow().validate()*/) {
int cellnum = firstHeaderColumn;
CTTableColumns ctTableColumns = table.getCTTable().getTableColumns();
if(ctTableColumns != null) {
for (CTTableColumn col : ctTableColumns.getTableColumnList()) {
XSSFCell cell = row.getCell(cellnum);
if (cell != null) {
col.setName(formatter.formatCellValue(cell));
}
cellnum++;
}
}
}
}

public static void main(String[] args) throws Exception {

String templatePath = "dummy_template.xlsx";
String outputPath = "result.xlsx";

FileInputStream inputStream = new FileInputStream(templatePath);
Workbook workbook = WorkbookFactory.create(inputStream);
Sheet sheet = workbook.getSheetAt(0);

Map<String, String> header = new HashMap<String, String>();
header.put("textone", "Spalte eins");
header.put("texttwo", "Spalte zwei");
header.put("textthree", "Spalte drei");

translateHeaders(sheet, header, 3);

XSSFTable table = ((XSSFSheet)sheet).getTables().get(0);

updateHeaders(table);

FileOutputStream outputStream = new FileOutputStream(outputPath);
workbook.write(outputStream);
outputStream.close();
workbook.close();

}
}

如果我打开 dummy_template.xlsx使用 Excel 2007然后另存为dummy_template2007.xlsx , 该行的 XML更改为

<row r="4" spans="1:3">

现在使用这个 dummy_template2007.xlsx无需手动调用 XSSFTable.updateHeaders是必要的。 XSSFTable.writeToXSSFTable.commit 调用自动执行此操作。

关于java - 使用 Apache Poi 重命名 XSSFTable 的 header 会导致损坏的 XLSX 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55532006/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com