为了账号安全,请及时绑定邮箱和手机立即绑定

重命名 XSSF 表的头与阿帕奇 Poi 导致损坏的 XLSX 文件

重命名 XSSF 表的头与阿帕奇 Poi 导致损坏的 XLSX 文件

HUX布斯 2022-09-22 19:47:20

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


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


我发现这个问题堆栈溢出已经 Excel文件被损坏,当我改变标题(列标题)中任何单元格的值,但它没有得到回答和相当旧。但是我试图弄清楚注释可能是什么,并试图平展现有的XSSFTable,将填充的数据复制到新工作表中,然后将新的XSSFTable放在数据上。可悲的是,这似乎非常复杂,所以我又回到了纠正破碎的标题单元格。我还尝试使用POI创建整个工作表,并避免使用该“模板”-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));

                }

            }

        });

}

“我的细胞之路”是一个组织,它遍历从左上角到右下角的单元格范围。


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


查看完整描述

1 回答

?
繁花不似锦

TA贡献1520条经验 获得超4个赞

好吧,XSSFTable.更新标题应该可以做到这一点,如果这样做不会失败的话。apache poi

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

我已经下载了你的,然后尝试更改工作表中的表格列标题。但即使调用了列名之后,在 中也没有改变。因此,我查看了 XSSFTable.java -> 更新标题以确定为什么不会发生这种情况。在那里,我们发现:dummy_template.xlsxXSSFTable.updateHeadersXSSFTable

if (row != null && row.getCTRow().validate()) {

 //do changing the column names

}

因此,仅当工作表中的相应行根据名称空格有效时,才会更改列名称。但在后来的版本中(2007年之后),增加了额外的命名空间。在本例中,该行如下所示:XMLOffice Open XMLExcelXML


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

请注意附加属性。这就是返回的原因。x14ac:dyDescentrow.getCTRow().validate()false


以下代码获取您的 ,重命名工作表中的列标题,然后调用解除版本。之后,在 中打开 有效。dummy_template.xlsxstatic void updateHeaders(XSSFTable table)result.xlsxExcel


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.xlsxExcel 2007dummy_template2007.xlsxXML


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


现在,在使用它时,无需手动调用。由 调用的 XSSFTable.write To 会自动执行此操作。dummy_template2007.xlsxXSSFTable.updateHeadersXSSFTable.commit


查看完整回答
反对 回复 2022-09-22

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信