Java使用poi获取不到docx表格中书签的问题及解决
作者:编程经验分享
这篇文章主要介绍了Java使用poi获取不到docx表格中书签的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
问题
实际项目中遇到个需求,需要替换 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); } } }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。