Reputation: 109
I need to merge two (or more, but let's stick to two) word documents (docx) with docx4j. My approach to merge is copy all body children from one document and append to another. Then, I just rearrange some stuff. I have been using it for two years, and it is fine for my purpose.
Here is a simple example:
first.docx = simple text
second.docx = simple text + image
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);
The problem is when I save. This errors come out:
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
Any light here to solve it?
1) I dont want altchunk, it sucks. 2) The commercial (Enterprise) version of docx4j can do it, but I'm looking for FOSS.
Thanks
Upvotes: 1
Views: 9147
Reputation: 51
Here we combined together from the posts a real working code:
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();
}
}
this snippet takes images with decoration in docx from s document to f document. Sysouts needed because of a reason I have forgotten but without it lib can not determine the mime of the image.
Upvotes: 3
Reputation: 15878
Manipulate the blips in s before adding them to f. In other words, swap the order of your for loops.
Then in your blip manipulation, what you need to do is:
Now add the content of s to f. You could just use addAll to do the job without the nested loop. Also there's only one body object, so you don't need the outer loop.
Obviously this answer is limited to handling only CTBlip, and then only embedded ones. There's a lot more to a complete solution to merging docx files...
Note: I wrote the code for merging documents in docx4j Enterprise
Upvotes: 3