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

获取行索引时出现 XmlValueDisconnectedException

获取行索引时出现 XmlValueDisconnectedException

万千封印 2023-04-19 16:08:34
在我的代码中,我逐行检查一个 XLSX 文件,并使用 Apache POI 4.1.0 对数据库进行验证。如果我发现不正确的行,我会通过将其添加到List<XSSFRow> toRemove. 在遍历每一行之后,这个小方法应该删除标记为删除的行:ListIterator<XSSFRow> rowIterator = toRemove.listIterator(toRemove.size());while (rowIterator.hasPrevious()) {    XSSFRow row = rowIterator.previous();    if (row != null && row.getSheet() == sheet) {        int lastRowNum = sheet.getLastRowNum();        int rowIndex = row.getRowNum();        if (rowIndex == lastRowNum) {            sheet.removeRow(row);        } else if (rowIndex >= 0 && rowIndex < lastRowNum) {            sheet.removeRow(row);        } else {            System.out.println("\u001B[31mERROR: Removal failed because row " + rowIndex + " is out of bounds\u001B[0m");        }        System.out.println("Row " + rowIndex + " successfully removed");    } else {        System.out.println("Row skipped in removal because it was null already");    }}getRowNum()但由于某些未知原因,它完美地删除了所有行,然后在获取最后(第一个添加的)行的行索引 ( ) 时抛出 XmlValueDisconnectedException 。Stacktrace的相关部分:org.apache.xmlbeans.impl.values.XmlValueDisconnectedException    at org.apache.xmlbeans.impl.values.XmlObjectBase.check_orphaned(XmlObjectBase.java:1258)    at org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTRowImpl.getR(Unknown Source)    at org.apache.poi.xssf.usermodel.XSSFRow.getRowNum(XSSFRow.java:400)    at Overview.removeRows(Overview.java:122)编辑:我也尝试更改迭代过程(见下文)但错误保持不变。for (XSSFRow row : toRemove) {   // same code as above without iterator and while}
查看完整描述

1 回答

?
偶然的你

TA贡献1841条经验 获得超3个赞

如果一行在 List 中被双重包含,则会发生错误toRemove。AList允许重复条目。所以同一行可能会被双重添加到List. 如果然后Iterator得到该行的第一次出现,这将从工作表中正确删除。但是,如果稍后再次出现同一行,则row.getRowNum()失败,因为该行不再存在于工作表中。


这是重现该行为的完整代码:


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


import java.io.FileInputStream;

import java.io.FileOutputStream;


import java.util.*;


public class ExcelRemoveRows {


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


  String filePath = "Excel.xlsx"; // must contain at least 5 filled rows


  Workbook workbook = WorkbookFactory.create(new FileInputStream(filePath));

  Sheet sheet = workbook.getSheetAt(0);


  List<Row> toRemoveList = new ArrayList<Row>();

  toRemoveList.add(sheet.getRow(0));

  toRemoveList.add(sheet.getRow(2));

  toRemoveList.add(sheet.getRow(4));

  toRemoveList.add(sheet.getRow(2)); // this produces the error


  System.out.println(toRemoveList); // contains row hawing index 2 (r="3") two times


  for (Row row : toRemoveList) {

   System.out.println(row.getRowNum()); // XmlValueDisconnectedException on second occurance of row index 2

   sheet.removeRow(row);

  }


  FileOutputStream out = new FileOutputStream("Changed"+filePath);

  workbook.write(out);

  out.close();

  workbook.close();

 }

}

解决方案是避免List多次包含同一行。


我不会收集要在 a 中删除的行List<XSSFRow>,而是收集要在 a 中删除的行号Set<Integer>。这将避免重复,因为 aSet不允许重复的元素。然后要删除的行可以简单地通过sheet.getRow(rowNum).


代码:


...

  Set<Integer> toRemoveSet = new HashSet<Integer>();

  toRemoveSet.add(sheet.getRow(0).getRowNum());

  toRemoveSet.add(sheet.getRow(2).getRowNum());

  toRemoveSet.add(sheet.getRow(4).getRowNum());

  toRemoveSet.add(sheet.getRow(2).getRowNum());


  System.out.println(toRemoveSet); // does not contain the row index 2 two times


  for (Integer rowNum : toRemoveSet) {

   Row row = sheet.getRow(rowNum);

   System.out.println(row.getRowNum());

   sheet.removeRow(row);

  }

...


查看完整回答
反对 回复 2023-04-19
  • 1 回答
  • 0 关注
  • 782 浏览

添加回答

举报

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