Bootstrap

poi-tl 合并 多个 word 文档 为一个(踩坑记录:tips:当合并一次word之后想要在书签指定位置再次合并word需要刷新word书签段落光标信息;问题:明明空间未绑定,)

使用poi-tl,合并word变得十分简单,只需要几行代码

示例如下:


1. pom版本:

     <dependency>
            <groupId>com.deepoove</groupId>
            <artifactId>poi-tl</artifactId>
            <version>1.12.1</version>
        </dependency>

2. 根据路径创建两个word 的document 对象,调用内置的merge() 方法即可以合并两个word 到一起,将documen2 追加到document 最后面。

代码如下:

NiceXWPFDocument document1 = new NiceXWPFDocument(Files.newInputStream(Paths.get("C:\\test\\test1.docx")));
NiceXWPFDocument document2 = new NiceXWPFDocument(Files.newInputStream(Paths.get("C:\\test\\test2.docx")));
document1 = document1.merge(document2);

poi-tl代码如下:
可以将多个word追加到合并当前word的指定位置

    public NiceXWPFDocument merge(NiceXWPFDocument docMerge) throws Exception {
        return merge(Arrays.asList(docMerge), createParagraph().createRun());
    }

    public NiceXWPFDocument merge(List<NiceXWPFDocument> docMerges, XWPFRun run) throws Exception {
        if (null == docMerges || docMerges.isEmpty() || null == run) return this;
        return merge(docMerges.iterator(), run);
    }

    public NiceXWPFDocument merge(Iterator<NiceXWPFDocument> iterator, XWPFRun run) throws Exception {
        XWPFRun newRun = run;
        String paragraphText = ParagraphUtils.trimLine((XWPFParagraph) run.getParent());
        boolean havePictures = ParagraphUtils.havePictures((XWPFParagraph) run.getParent());
        if (!ParagraphUtils.trimLine(run.text()).equals(paragraphText) || havePictures) {
            BodyContainer container = BodyContainerFactory.getBodyContainer(run);
            XWPFParagraph paragraph = container.insertNewParagraph(run);
            newRun = paragraph.createRun();
        }
        return new XmlXWPFDocumentMerge().merge(this, iterator, newRun);
    }

    public NiceXWPFDocument merge(NiceXWPFDocument source, Iterator<NiceXWPFDocument> mergeIterator, XWPFRun run)
            throws Exception {
        CTBody body = source.getDocument().getBody();
        List<String> addParts = createMergeableStrings(source, mergeIterator);
        String[] startEnd = truncatedStartEndXmlFragment(body);

        XWPFParagraph paragraph = (XWPFParagraph) run.getParent();
        CTP mergedContainer = paragraph.getCTP();
        CTP mergedBody = CTP.Factory
                .parse(startEnd[0] + "<w:POITL>" + String.join("", addParts) + "</w:POITL>" + startEnd[1]);
        // instead insert xml-fragment?
        mergedContainer.set(mergedBody);
        String xmlText = truncatedOverlapWP(body);
        body.set(CTBody.Factory.parse(xmlText));
        return source.generate(true);
    }

遇到的问题:多次合并只能追加,不能指定位置连续合并?

事先准备好需要插入的书签位置,当第一次插入后后续需要刷新书签对应段落信息,否则会出现:Method threw 'org.apache.xmlbeans.impl.values.XmlValueDisconnectedException' exception. Cannot evaluate org.openxmlformats.schemas.wordprocessingml.x2006.main.impl.CTPImpl.toString()错误
解决方案:每次合并完word文档 需要刷新书签对应段落信息数据。

2024-6-4 新增

问题:error: 与元素类型 "w:t" 相关联的属性 "xsi:nil" 的前缀 "xsi" 未绑定。
解决代码:

                // 添加命名空间
                org.w3c.dom.Element domNode = (org.w3c.dom.Element) document.getDocument().getBody().getDomNode();
                DocumentHelper.addNamespaceDeclaration(domNode,"xsi","http://www.w3.org/2001/XMLSchema-instance");

;