如何用Apache POI 5.2.3删除指定XSSFSingleXmlCell且不影响其他XML映射?
解决Apache POI删除单个XML映射关联单元格不影响其他映射的问题
你的核心问题在于:一个SingleXmlCells对象可能包含多个属于不同XML映射的XSSFSingleXmlCell,直接删除整个SingleXmlCells会误删其他映射的关联单元格。正确的做法是仅移除当前目标映射对应的单个XML单元格,只有当SingleXmlCells为空时才删除整个关联对象。
以下是修改后的关键代码,替换原有的removeXmlMappingsForSingleCells方法,并新增辅助方法来处理单个单元格的移除:
private static boolean removeXmlMappingsForSingleCells(XSSFWorkbook workbook, MapInfo mapInfo, XSSFMap xssfMap) { int targetMapId = xssfMap.getCtMap().getID(); int sheetNumber = workbook.getNumberOfSheets(); for (int i = 0; i < sheetNumber; i++) { XSSFSheet sheet = workbook.getSheetAt(i); Iterator<POIXMLDocumentPart> relationsIterator = sheet.getRelations().iterator(); while (relationsIterator.hasNext()) { POIXMLDocumentPart part = relationsIterator.next(); if (part instanceof SingleXmlCells singleXmlCells) { List<XSSFSingleXmlCell> cellsToRemove = new ArrayList<>(); // 收集当前SingleXmlCells中属于目标映射的单元格 for (XSSFSingleXmlCell cell : singleXmlCells.getAllSimpleXmlCell()) { if (cell.getMapId() == targetMapId) { cellsToRemove.add(cell); } } // 移除目标单元格 for (XSSFSingleXmlCell cellToRemove : cellsToRemove) { removeSingleXmlCell(singleXmlCells, cellToRemove); } // 如果移除后SingleXmlCells为空,删除整个关联 if (singleXmlCells.getAllSimpleXmlCell().isEmpty()) { try { Method removeRelation = POIXMLDocumentPart.class.getDeclaredMethod("removeRelation", POIXMLDocumentPart.class, boolean.class); removeRelation.setAccessible(true); Boolean success = (Boolean) removeRelation.invoke(sheet, part, true); if (!Boolean.TRUE.equals(success)) { log.error("Failed to remove empty SingleXmlCells relation from sheet {}", sheet.getSheetName()); return false; } } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { log.error("Could not execute method 'removeRelation'!", e); return false; } } } } } return true; } private static void removeSingleXmlCell(SingleXmlCells singleXmlCells, XSSFSingleXmlCell cellToRemove) { // 获取底层CT对象,移除对应的单个XML单元格配置 org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSingleXmlCells ctSingleXmlCells = singleXmlCells.getCTSingleXmlCells(); List<org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSingleXmlCell> ctCells = ctSingleXmlCells.getSingleXmlCellList(); Iterator<org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSingleXmlCell> ctIterator = ctCells.iterator(); while (ctIterator.hasNext()) { org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSingleXmlCell ctCell = ctIterator.next(); // 通过mapId和xpath匹配目标单元格(确保准确移除) if (ctCell.getMapId() == cellToRemove.getMapId() && ctCell.getXpath().equals(cellToRemove.getXpath())) { ctIterator.remove(); break; } } }
关键修改说明:
- 精准定位目标单元格:遍历每个
SingleXmlCells,只收集属于当前要删除的XML映射的XSSFSingleXmlCell - 操作底层CT对象移除单个单元格:因为POI没有直接提供删除
XSSFSingleXmlCell的API,所以直接操作OpenXML的CT对象来移除对应的配置 - 按需删除关联对象:只有当
SingleXmlCells中没有剩余单元格时,才删除整个POIXMLDocumentPart关联,避免影响其他映射的单元格
这样修改后,就能仅删除指定XML映射关联的单个单元格,不会误删其他映射的内容。
内容的提问来源于stack exchange,提问作者Thomas T.
相关产品推荐
相关产品推荐

