java POI合並兩個Word后打開生成后的doxc提示 The file is corrupt and cannot be opened


問題描述:

java后端使用 Apache 的 POI導出 Word,涉及到兩個 Word 模板合並的時候,合並后的文件打開出現下圖中的問題!

問題發現:

找了一圈最后在博客 java開發doxc下載提示 The file is corrupt and cannot be opened找到解決辦法。

問題排查:

該博客中提到是 <w:sectPr> 標簽的問題,由此我寫了一個標簽匹配方法

    /** 獲取指定標簽中的內容
     * @param xml
     * @param label
     * @return
     */
    public static String regex(String xml, String label) {
        String context = "";
        // 正則表達式
        String rgex = "<" + label + "[^>]*>((?:(?!<\\/" + label + ">)[\\s\\S])*)<\\/" + label + ">";
        Pattern pattern = Pattern.compile(rgex);// 匹配的模式
        Matcher m = pattern.matcher(xml);
        // 匹配的有多個
        List<String> list = new ArrayList<String>();
        while (m.find()) {
            int i = 1;
            list.add(m.group(i));
            i++;
        }
        if (list.size() > 0) {
            // 輸出內容自己定義
            context = String.valueOf(list.size());
        }
        return context;
    }

然后在 POI 合並的時候檢查一下 POI 將 Word 轉為 xml 后 w:sectPr 標簽情況

    /** 兩個對象進行追加
     * 2019-06-26 houzw添加
     * @param src 目標文檔
     * @param append 子文檔
     * @return
     * @throws Exception
     */
    public static XWPFDocument mergeWord(XWPFDocument src, XWPFDocument append) throws Exception {
//        XWPFParagraph paragraph = src.createParagraph();
//        //設置分頁符
//        paragraph.setPageBreak(true);

        CTBody src1Body = src.getDocument().getBody();
        CTBody src2Body = append.getDocument().getBody();

        List<XWPFPictureData> allPictures = append.getAllPictures();
        // 記錄圖片合並前及合並后的ID
        Map<String, String> map = new HashMap();
        for (XWPFPictureData picture : allPictures) {
            String before = append.getRelationId(picture);
            // 將原文檔中的圖片加入到目標文檔中
            String after = src.addPictureData(picture.getData(), Document.PICTURE_TYPE_PNG);
            map.put(before, after);
        }

        appendBody(src1Body, src2Body, map);

        return src;

    }

    private static void appendBody(CTBody src, CTBody append, Map<String, String> map) throws Exception {
        XmlOptions optionsOuter = new XmlOptions();
        optionsOuter.setSaveOuter();
        String appendString = append.xmlText(optionsOuter);

        String srcString = src.xmlText();
        String regex = regex(srcString, "w:sectPr");
        System.out.println(regex);
        String prefix = srcString.substring(0, srcString.indexOf(">") + 1);
        String mainPart = srcString.substring(srcString.indexOf(">") + 1, srcString.lastIndexOf("<"));
        String sufix = srcString.substring(srcString.lastIndexOf("<"));
        String addPart = appendString.substring(appendString.indexOf(">") + 1, appendString.lastIndexOf("<"));

        if (map != null && !map.isEmpty()) {
            // 對xml字符串中圖片ID進行替換
            for (Map.Entry<String, String> set : map.entrySet()) {
                addPart = addPart.replace(set.getKey(), set.getValue());
            }
        }
        // 將兩個文檔的xml內容進行拼接
        CTBody makeBody = CTBody.Factory.parse(prefix + mainPart + addPart + sufix);

        src.set(makeBody);
    }

合並三個 word 文檔,結果輸出 2 也就是說前兩個文檔合並后 w:sectPr 標簽有兩個。因為我輸出的是目標模板合並前的 w:sectPr 標簽情況。
具體的 w:sectPr 標簽內容如下:

<w:sectPr w:rsidR="003D0B45" w:rsidRPr="003D0B45"><w:footerReference w:type="first" r:id="rId7"/><w:pgSz w:w="11907" w:h="16840"/><w:pgMar w:top="1440" w:right="1797" w:bottom="1440" w:left="1797" w:header="851" w:footer="992" w:gutter="0"/><w:cols w:space="720"/><w:titlePg/><w:docGrid w:type="lines" w:linePitch="312"/></w:sectPr>

解決具體方法

去掉追加word內容中的 w:sectPr 標簽,確保合成的word中只有一個 w:sectPr 標簽對

        String rgex = "<[\\s]*?w:sectPr[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?w:sectPr[\\s]*?>";
        appendString = appendString.replaceAll(rgex, "");

至此問題解決!問題總是具有片面性,真誠希望各位看官斧正,有新的觀點留言我,大家一起交流學習。

謝謝各位,祝大家玩的開心。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM