使用DOCX4J合并单词(docx)文档:如何复制图像?

时间:2014-05-22 01:36:02

标签: java openxml docx docx4j

我需要将两个(或更多,但让我们坚持两个)word文档(docx)与docx4j合并。我的合并方法是从一个文档中复制所有正文子项并附加到另一个文档。然后,我只是重新排列一些东西。我已经使用它两年了,这对我的目的来说很好。

这是一个简单的例子:

first.docx =简单文字
second.docx =简单文字+图片

    File first = new File("first.docx");
    File second = new File("second.docx");

    WordprocessingMLPackage f = WordprocessingMLPackage.load(first);
    WordprocessingMLPackage s = WordprocessingMLPackage.load(second);

    List body = s.getMainDocumentPart().getJAXBNodesViaXPath("//w:body", false);
    for(Object b : body){
        List filhos = ((org.docx4j.wml.Body)b).getContent();
        for(Object k : filhos)
            f.getMainDocumentPart().addObject(k);
    }

    List blips = s.getMainDocumentPart().getJAXBNodesViaXPath("//a:blip", false);
    for(Object el : blips){
        try {
            CTBlip blip = (CTBlip) el;

            RelationshipsPart parts = s.getMainDocumentPart().getRelationshipsPart();
            Relationship rel = parts.getRelationshipByID(blip.getEmbed());

            RelationshipsPart docRels = f.getMainDocumentPart().getRelationshipsPart();

            rel.setId(null);
            docRels.addRelationship(rel);
            blip.setEmbed(rel.getId());

            f.getMainDocumentPart().addTargetPart(s.getParts().getParts().get(new PartName("/word/"+rel.getTarget())));

        } catch (Exception ex){}
    }

    File saved = new File("saved.docx");
    f.save(saved);

    Desktop.getDesktop().open(saved);

问题出在我保存的时候。这个错误出来了:

    org.docx4j.openpackaging.exceptions.Docx4JException: Failed to add parts from relationships of /
at org.docx4j.openpackaging.io3.Save.addPartsFromRelationships(Save.java:390)
at org.docx4j.openpackaging.io3.Save.save(Save.java:192)
at org.docx4j.openpackaging.packages.OpcPackage.save(OpcPackage.java:441)
at org.docx4j.openpackaging.packages.OpcPackage.save(OpcPackage.java:406)

Caused by: org.docx4j.openpackaging.exceptions.Docx4JException: Failed to add parts from relationships of /word/document.xml
at org.docx4j.openpackaging.io3.Save.addPartsFromRelationships(Save.java:390)
at org.docx4j.openpackaging.io3.Save.savePart(Save.java:442)
at org.docx4j.openpackaging.io3.Save.addPartsFromRelationships(Save.java:385)
... 4 more

Caused by: org.docx4j.openpackaging.exceptions.Docx4JException: Failed to put binary part
at
org.docx4j.openpackaging.io3.stores.ZipPartStore.saveBinaryPart(ZipPartStore.java:398)
at org.docx4j.openpackaging.io3.Save.savePart(Save.java:418)
at org.docx4j.openpackaging.io3.Save.addPartsFromRelationships(Save.java:385)
... 6 more

Caused by: java.io.IOException: part '/word/media/image1.jpg' not found
at
org.docx4j.openpackaging.io3.stores.ZipPartStore.saveBinaryPart(ZipPartStore.java:361)
... 8 more

Exception in thread "main" org.docx4j.openpackaging.exceptions.Docx4JException: Failed to add parts from relationships of /
at org.docx4j.openpackaging.io3.Save.addPartsFromRelationships(Save.java:390)
at org.docx4j.openpackaging.io3.Save.save(Save.java:192)
at org.docx4j.openpackaging.packages.OpcPackage.save(OpcPackage.java:441)
at org.docx4j.openpackaging.packages.OpcPackage.save(OpcPackage.java:406)

Caused by: org.docx4j.openpackaging.exceptions.Docx4JException: Failed to add parts from relationships of /word/document.xml
at org.docx4j.openpackaging.io3.Save.addPartsFromRelationships(Save.java:390)
at org.docx4j.openpackaging.io3.Save.savePart(Save.java:442)
at org.docx4j.openpackaging.io3.Save.addPartsFromRelationships(Save.java:385)
... 4 more

Caused by: org.docx4j.openpackaging.exceptions.Docx4JException: Failed to put binary part
at
org.docx4j.openpackaging.io3.stores.ZipPartStore.saveBinaryPart(ZipPartStore.java:398)
at org.docx4j.openpackaging.io3.Save.savePart(Save.java:418)
at org.docx4j.openpackaging.io3.Save.addPartsFromRelationships(Save.java:385)
... 6 more

Caused by: java.io.IOException: part '/word/media/image1.jpg' not found
at
org.docx4j.openpackaging.io3.stores.ZipPartStore.saveBinaryPart(ZipPartStore.java:361)
... 8 more

这里有什么解决方法吗?

1)我不想要altchunk,它很糟糕。 2)docx4j的商业(企业)版本可以做到,但我正在寻找FOSS。

由于

2 个答案:

答案 0 :(得分:2)

在将它们添加到f之前操作s中的blip。换句话说,交换for循环的顺序。

然后在你的blip操作中,你需要做的是:

  • 获得感兴趣的部分
  • Rel rel = f.getMainDocumentPart()。addTargetPart
  • 从rel.getId
  • 更新blip中的relId

现在将s的内容添加到f。你可以使用addAll来完成没有嵌套循环的工作。此外,只有一个身体对象,所以你不需要外环。

显然,这个答案仅限于处理CTBlip,然后只处理嵌入的CTBlip。对于合并docx文件的完整解决方案还有很多......

注意:我编写了在docx4j Enterprise中合并文档的代码

答案 1 :(得分:1)

在这里,我们从帖子中将实际工作代码组合在一起:

List<Object> blips = s.getMainDocumentPart().getJAXBNodesViaXPath("//a:blip", false);
    for(Object el : blips){
        try {

               CTBlip blip = (CTBlip) el;
               RelationshipsPart parts = s.getMainDocumentPart().getRelationshipsPart();
               Relationship rel = parts.getRelationshipByID(blip.getEmbed());
               Part part = parts.getPart(rel);
               if(part instanceof ImagePngPart)
                    System.out.println(((ImagePngPart) part).getBytes()); 
               if(part instanceof ImageJpegPart)
                    System.out.println(((ImageJpegPart) part).getBytes()); 
                if(part instanceof ImageBmpPart)
                    System.out.println(((ImageBmpPart) part).getBytes()); 
                if(part instanceof ImageGifPart)
                    System.out.println(((ImageGifPart) part).getBytes()); 
                if(part instanceof ImageEpsPart)
                    System.out.println(((ImageEpsPart) part).getBytes()); 
                if(part instanceof ImageTiffPart)
                    System.out.println(((ImageTiffPart) part).getBytes()); 
                Relationship newrel = f.getMainDocumentPart().addTargetPart(part,AddPartBehaviour.RENAME_IF_NAME_EXISTS);
                blip.setEmbed(newrel.getId());
                f.getMainDocumentPart().addTargetPart(s.getParts().getParts().get(new PartName("/word/"+rel.getTarget())));
            } catch (Exception ex){
                    ex.printStackTrace();
            } }

此代码段将docx中装饰的图像从s文档转换为f文档。 Sysouts需要因为我忘记的原因但没有它lib无法确定图像的哑剧。