SoFunction
Updated on 2025-03-10

The problem of using poi to obtain bookmarks in docx tables and solutions

question

I encountered a requirement in the actual project and needed to replace the content of the bookmark in docx.

Use poi to read the bookmark of docx, directly obtain the bookmark of paragraphs (paragraph) in the document and then replace the content. After processing, it is found that the bookmarks in the table in the document have not been replaced

How to solve it

The content in each cell in the document is also a paragraph. The bookmarks in the table are processed separately. First, all cells (cells) of all tables, and then the paragraphs are obtained for bookmark replacement.

Code

How to replace bookmarks

public class WordUtil {

    /**
      * Process bookmarks in tables The contents in each cell can be regarded as a paragraph
      *
      * @param xwpfDocument Document object
      * @param dataMap Bookmark content
      */
    public static void dealBookmarkOfDocx(XWPFDocument xwpfDocument, Map<String, String> dataMap) throws IOException {
        //Processing bookmarks in the form        List<XWPFTable> tableList = ();
        for (XWPFTable table : tableList) {
            int rowCount = ();//Get the number of rows of table            for (int i = 0; i < rowCount; i++) {
                XWPFTableRow row = (i);
                List<XWPFTableCell> cells = ();
                for (XWPFTableCell cell : cells) {
                    dealParagraphBookmark((), dataMap);
                }
            }
        }
        //Processing bookmarks in paragraphs        List<XWPFParagraph> paragraphs = ();
        dealParagraphBookmark(paragraphs, dataMap);
    }

    /**
      * Replace the bookmark in each paragraph
      *
      * @param paragraphList paragraph list
      * @param dataMap Bookmark content
      */
    private static void dealParagraphBookmark(List<XWPFParagraph> paragraphList, Map<String, String> dataMap) {
        for (XWPFParagraph paragraph : paragraphList) {
            CTP ctp = ();
            for (int i = 0; i < (); i++) {
                CTBookmark bookmark = (i);
                String bookmarkName = ();
                if ((bookmarkName)) {
                    XWPFRun xwpfRun = ();
                    ((bookmarkName));

                    Node firstNode = ();
                    Node nextNode = ();
                    while (nextNode != null) {
                        String nodeName = ();
                        if (("w:bookmarkEnd")) {
                            break;
                        }
                        Node delNode = nextNode;
                        nextNode = ();
                        ().removeChild(delNode);
                    }
                    if (nextNode == null) {
                        //The end sign cannot be found, add it in front of the bookmark                        ().insertBefore(().getDomNode(), firstNode);
                    } else {
                        //Find the ending character and add the new content before the ending character, that is, the content is written to the middle of the bookmark                        ().insertBefore(().getDomNode(), nextNode);
                    }
                }
            }
        }
    }
}

test

class WordUtilTest {

    @Test
    void dealBookmarkOfDocx() {
        String docxPath = "C:\\Users\\XXX\\Desktop\\";

        Map<String, String> dataMap = new HashMap<>();
        ("bookmark1", "1234567");

        try (InputStream inputStream = ((docxPath));
             XWPFDocument xDoc = new XWPFDocument(inputStream)) {

            (xDoc, dataMap);

            (((docxPath)));

        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}

Summarize

The above is personal experience. I hope you can give you a reference and I hope you can support me more.