目录
问题
实际项目中遇到个需求,需要替换 docx 中书签的内容。
使用 poi 读取 docx 的书签,直接获取文档中的段落(paragraph)的书签然后进行替换内容,处理完后发现文档中表格里的书签并没有被替换
如何解决
文档中每个单元格里的内容也是段落(paragraph),将表格中的书签做单独处理,先获取所有表格(table)所有单元格(cell),再获取段落进行书签替换即可
代码
替换书签方法
public class WordUtil {
/**
* 处理表格中的书签 每个单元格里的内容都可以看作一个段落
*
* @param xwpfDocument 文档对象
* @param dataMap 书签内容
*/
public static void dealBookmarkOfDocx(XWPFDocument xwpfDocument, Map<String, String> dataMap) throws IOException {
//处理表格中的书签
List<XWPFTable> tableList = xwpfDocument.getTables();
for (XWPFTable table : tableList) {
int rowCount = table.getNumberOfRows();//获取table的行数
for (int i = 0; i < rowCount; i++) {
XWPFTableRow row = table.getRow(i);
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
dealParagraphBookmark(cell.getParagraphs(), dataMap);
}
}
}
//处理段落里的书签
List<XWPFParagraph> paragraphs = xwpfDocument.getParagraphs();
dealParagraphBookmark(paragraphs, dataMap);
}
/**
* 替换每个段落中的书签
*
* @param paragraphList 段落list
* @param dataMap 书签内容
*/
private static void dealParagraphBookmark(List<XWPFParagraph> paragraphList, Map<String, String> dataMap) {
for (XWPFParagraph paragraph : paragraphList) {
CTP ctp = paragraph.getCTP();
for (int i = 0; i < ctp.sizeOfBookmarkEndArray(); i++) {
CTBookmark bookmark = ctp.getBookmarkStartArray(i);
String bookmarkName = bookmark.getName();
if (dataMap.containsKey(bookmarkName)) {
XWPFRun xwpfRun = paragraph.createRun();
xwpfRun.setText(dataMap.get(bookmarkName));
Node firstNode = bookmark.getDomNode();
Node nextNode = firstNode.getNextSibling();
while (nextNode != null) {
String nodeName = nextNode.getNodeName();
if (nodeName.equalsIgnoreCase("w:bookmarkEnd")) {
break;
}
Node delNode = nextNode;
nextNode = nextNode.getNextSibling();
ctp.getDomNode().removeChild(delNode);
}
if (nextNode == null) {
//找不到结束标识,在书签前面加
ctp.getDomNode().insertBefore(xwpfRun.getCTR().getDomNode(), firstNode);
} else {
//找到结束符,将新内容添加到结束符之前,即内容写入bookmark中间
ctp.getDomNode().insertBefore(xwpfRun.getCTR().getDomNode(), nextNode);
}
}
}
}
}
}
测试
class WordUtilTest {
@Test
void dealBookmarkOfDocx() {
String docxPath = "C:\\Users\\XXX\\Desktop\\myDoc.docx";
Map<String, String> dataMap = new HashMap<>();
dataMap.put("bookmark1", "1234567");
try (InputStream inputStream = Files.newInputStream(Paths.get(docxPath));
XWPFDocument xDoc = new XWPFDocument(inputStream)) {
WordUtil.dealBookmarkOfDocx(xDoc, dataMap);
xDoc.write(Files.newOutputStream(Paths.get(docxPath)));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}