Search code examples
javadocx4j

Find the owning Part of a node element with docx4j


I've got a list of placeholders in my DOCX document I've referenced this way :

private void findPlaceHolders() {
    Docx4JPlaceHolderFinder finder = new Docx4JPlaceHolderFinder();
    TraversalUtil.visit(document, false, finder);
    placeHoldersRegister = new HashMap<>(finder.getFoundPlaceHolders());
}

Docx4JPlaceHolderFinder is an implementation of CallbackImpl, finding all ContentAccessor (mostly R) instance containing text value of this form : $[placeholder_name].

placeHolderRegister is an instance of HashMap<String, List<ContentAccessor>> ; it associates lists of ContentAccessor instances with their corresponding placeholder keyword.

I want to be able to insert picture in those placeholders. Here is the complete source code of my Docx4JImageMailMerger class :

package org.johndoe.fwk.simplefile.implementation.docxutil;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.docx4j.TraversalUtil;
import org.docx4j.dml.wordprocessingDrawing.Inline;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.Part;
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
import org.docx4j.wml.ContentAccessor;
import org.docx4j.wml.Drawing;
import org.docx4j.wml.ObjectFactory;

import org.johndoe.fwk.exception.ExceptionFwk;

/**
 * Classe dédiée au publipostage d'image dans un document Docx4J.
 */
public class Docx4JImageMailMerger {

    private final ObjectFactory factory;
    private WordprocessingMLPackage document;
    private Map<String, List<ContentAccessor>> placeHoldersRegister;

    public Docx4JImageMailMerger(WordprocessingMLPackage document) {
        this.factory = new ObjectFactory();
        this.document = document;
    }

    public void setImage(String placeHolderName, File imageFile) {
        setImage(placeHolderName, imageFile, null);
    }

    public void setImage(String placeHolderName, File imageFile, Long width) {
        List<ContentAccessor> placeHolders = selectPlaceHolders(placeHolderName);

        for (ContentAccessor placeHolder : placeHolders) {
            cleanPlaceHolder(placeHolder);
            includeImage(placeHolder, imageFile, width);
        }
    }

    private List<ContentAccessor> selectPlaceHolders(String imageName) {
        if (placeHoldersRegister == null)
            findPlaceHolders();

        List<ContentAccessor> selectedPlaceHolders = new ArrayList<>();
        selectedPlaceHolders.addAll(placeHoldersRegister.get(imageName));
        return selectedPlaceHolders;
    }

    private void findPlaceHolders() {
        Docx4JPlaceHolderFinder finder = new Docx4JPlaceHolderFinder();
        TraversalUtil.visit(document, false, finder);
        placeHoldersRegister = new HashMap<>(finder.getFoundPlaceHolders());
    }

    private void cleanPlaceHolder(ContentAccessor placeHolder) {
        placeHolder.getContent().clear();
    }

    private void includeImage(ContentAccessor placeHolder, File imageFile, Long width) {
        try {
            Part part = getOwningPart(placeHolder);
            BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(document, part, imageFile);

            Inline inline;
            if (width == null)
                inline = imagePart.createImageInline(imageFile.getName(), "test", 0, 1, false);
            else
                inline = imagePart.createImageInline(imageFile.getName(), "test", 0, 1, width, false);

            Drawing drawing = factory.createDrawing();
            drawing.getAnchorOrInline().add(inline);
            placeHolder.getContent().add(drawing);

        } catch (Exception e) {
            throw new ExceptionFwk("Erreur lors de l'inclusion de l'image", e);
        }
    }

    private Part getOwningPart(ContentAccessor placeHolder) {
        // What should I do here ?
    }

}

I don't know in which part of my document is the selected placeholder : body, header, footer, etc. The problem is I must determine it for BinaryPartAbstractImage.createImagePart(document, part, imageFile).

Is there any way I could get the Part instance to which my element belongs to ?


Solution

  • Generally speaking, given say a P object, you can call getParent() to find its parent object.

    But those objects don't know which part they are associated with.

    When you first find your place holders using your Docx4JPlaceHolderFinder, you are going to need to record the part in which they are found. Or change your approach to do the processing part by part.