Apache POI Word 新创建行无法垂直合并单元格如何解决
解决方案
问题根源是手动解析CTRow构造XWPFTableRow再插入表格的方式,会导致新行单元格与表格的内部关联属性缺失,后续设置的垂直合并标记无法被Word正确识别,最终合并失效。
你可以按照以下步骤修改代码,无需拆分保存读取流程即可实现需求:
- 替换自定义创建新行的逻辑,使用XWPFTable原生的插入行方法创建新行,再复制原行的样式和内容,保证表格内部属性关联正常
- 合并方法中新增原有垂直合并属性的清理逻辑,避免残留属性干扰
修改后的完整可运行代码如下:
import org.apache.poi.xwpf.usermodel.*; import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; public class POIWordAddSubRowQuestionDemo{ public static void main(String[] args) throws IOException{ ClassLoader classLoader = POIWordAddSubRowQuestionDemo.class.getClassLoader(); InputStream inputStream = classLoader.getResourceAsStream("input.docx"); String outputDocxPath = "F:/TEMP/output.docx"; assert inputStream != null; XWPFDocument doc = new XWPFDocument(inputStream); XWPFTable table = doc.getTables().get(0); //this is 'old row 2' XWPFTableRow secondRow = table.getRows().get(1); // 替换原来的自定义行创建逻辑,使用原生插入行方法 XWPFTableRow newRow = table.insertNewTableRow(2); // 复制old row 2的所有单元格样式和内容 for (int i = 0; i < secondRow.getTableCells().size(); i++) { XWPFTableCell sourceCell = secondRow.getCell(i); XWPFTableCell targetCell = newRow.addNewTableCell(); // 复制单元格样式 if (sourceCell.getCTTc().isSetTcPr()) { targetCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr()); } // 复制段落内容 targetCell.removeParagraph(0); for (XWPFParagraph sourcePara : sourceCell.getParagraphs()) { XWPFParagraph targetPara = targetCell.addParagraph(); targetPara.getCTP().set(sourcePara.getCTP()); } } // 设置新行第二列文本 XWPFRun xwpfRun = newRow.getCell(1).getParagraphs().get(0).getRuns().get(0); xwpfRun.setText("new row", 0); //merge cells at first column of 'old row 2', 'new row', and 'old row 3' mergeCellVertically(doc.getTables().get(0), 0, 1, 3); FileOutputStream fos = new FileOutputStream(outputDocxPath); doc.write(fos); fos.close(); doc.close(); } static void mergeCellVertically(XWPFTable table, int col, int fromRow, int toRow) { for(int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) { XWPFTableCell cell = table.getRow(rowIndex).getCell(col); CTVMerge vmerge = CTVMerge.Factory.newInstance(); if(rowIndex == fromRow){ // 首个合并单元格设置RESTART标记 vmerge.setVal(STMerge.RESTART); } else { // 合并到首格的单元格设置CONTINUE标记并清空内容 vmerge.setVal(STMerge.CONTINUE); for (int i = cell.getParagraphs().size(); i > 0; i--) { cell.removeParagraph(0); } cell.addParagraph(); } CTTcPr tcPr = cell.getCTTc().getTcPr(); if (tcPr == null) tcPr = cell.getCTTc().addNewTcPr(); // 先清空原有垂直合并标记,避免残留干扰 if (tcPr.isSetVMerge()) { tcPr.unsetVMerge(); } tcPr.setVMerge(vmerge); } } }
修改后直接运行即可实现你需要的合并效果,无需额外的保存读取步骤。
内容的提问来源于stack exchange,提问作者fall
相关产品推荐
相关产品推荐

