首页 > 解决方案 > docx4j / xlsx4j - 为什么 Row 忽略具有空值的单元格

问题描述

我目前在项目中使用org.docx4j:docx4j-JAXB-ReferenceImpl:11.2.9

在遍历 Excel 工作表时,我需要读取所有单元格值,甚至是那些为空的单元格值。

        File excelFile = new File("c:\report.xlsx");
        SpreadsheetMLPackage xlsxPkg = SpreadsheetMLPackage.load(excelFile);
        WorkbookPart workbookPart = xlsxPkg.getWorkbookPart();
        WorksheetPart sheet = workbookPart.getWorksheet(0);
        Worksheet ws = sheet.getContents();
        SheetData data = ws.getSheetData();
        data.getRow().forEach(row -> {
            row.getC().forEach(cell -> {
                LOG.debug(cell.getR());
            });
        });

我在 LOG 输出中注意到空单元格根本不存在。所以这意味着调用row.getC()返回的单元格数量减少了。这是日志输出的一部分。我在单元格R中添加了缺失的值。

2021-09-03 17:17:39,026 DEBUG ExcelParser [Test worker] Z2
2021-09-03 17:17:39,026 DEBUG ExcelParser [Test worker] AA2
                                                            AB2  <------- missing
2021-09-03 17:17:39,026 DEBUG ExcelParser [Test worker] AC2
                                                            AD2  <------- missing
2021-09-03 17:17:39,026 DEBUG ExcelParser [Test worker] AE2
                                                            AF2  <------- missing
2021-09-03 17:17:39,026 DEBUG ExcelParser [Test worker] AG2
2021-09-03 17:17:39,026 DEBUG ExcelParser [Test worker] AH2
2021-09-03 17:17:39,026 DEBUG ExcelParser [Test worker] AI2
2021-09-03 17:17:39,026 DEBUG ExcelParser [Test worker] AJ2
2021-09-03 17:17:39,026 DEBUG ExcelParser [Test worker] AK2
2021-09-03 17:17:39,026 DEBUG ExcelParser [Test worker] AL2

任何想法是什么原因造成的?我没有找到任何我应该应用的配置。问题是我需要稍后重新创建工作表,但是由于缺少空单元格,这正在移动其他值并将它们放在错误的列中。

标签: javaexceljaxbxlsxdocx4j

解决方案


在 Excel 文件中存储空单元格没有多大价值,因此只有具有某种内容的单元格才会存储在文件中。这不是一个错误,它只是它的实现方式。

如果您希望行是一个类似数组的结构,您可以使用此代码,其中所有单元格(填充或空)都有一个位置。我们从一个数组开始,其中所有位置都用空值填充。然后我们将所有有值的单元格放入数组中正确的位置。

public Cell[] getRow(Row row) {
  Cell[] row = new Cell[100]; // whatever number you choose as last column
  row.getC().forEach(cell -> {
    row[addresstoColumnNumber(cell.getR())] = cell;
  });
  return row;
}

public int addressToColumnNumber(String address) {
  String columnString = address.replaceAll("[0-9]", "");
  int number = 0;
  for (int i = 0; i < columnString.length(); i++) {
    number = number * 26 + (columnString.charAt(i) - ('A'-1));
  }
  return number - 1; // array index is zero-based
}

推荐阅读