MarekChr
MarekChr

Reputation: 1160

How to set all unset variables in docx template to empty string using docx4j?

I have defined some variables in my .docx document using ${<VAR NAME HERE>}. Then I use VariablePrepare.prepare(doc) and document.getMainDocumentPart().variableReplace(placeholders) methods to replace these variables using map data. However if some of the variables are not present in map, resulting variable is set to variable name.

VariablePrepare.prepare(document);
val placeholders = new HashMap<>(PLACEHOLDERS_STATIC);
if (data != null) {
    final HashMap<String, String> dynamicPlaceholders = new HashMap<>() {{
            put("firstName", "First name");
            put("firstNameVal", data.getFirstName());
            put("childTable", "Child");
            put("lastName", "Last name");
    }};
    placeholders.putAll(dynamicPlaceholders);
    document.getMainDocumentPart().variableReplace(placeholders);
}

Template:

enter image description here

After saving variable replaced doc: enter image description here

I would like the unfilled variables to be an empty string not their name. Is this possible to do in docx4j? Filling all keys with empty string as values to map is time consuming while having a lot of documents.

Dependency:

<dependency>
    <groupId>org.docx4j</groupId>
    <artifactId>docx4j-JAXB-ReferenceImpl</artifactId>
    <version>11.4.9</version>
</dependency>

Upvotes: 0

Views: 151

Answers (1)

JasonPlutext
JasonPlutext

Reputation: 15878

There is nothing built-in to do this, but you could try something like:

public static class TraversalUtilTextVisitor extends TraversalUtilVisitor<Text> {
    
    @Override
    public void apply(Text text, Object parent, List<Object> siblings) {

        if (text.getValue().contains("${")
                ) {
            
            int startPos = text.getValue().indexOf("${");
            int endPos = text.getValue().indexOf("}", startPos);
            if (endPos > -1) {
                text.setValue(text.getValue().substring(0, startPos) + text.getValue().substring(endPos+1));
            } else {
                System.out.println("Malformed variable in " + text.getValue());
            }
        }
    }

}   

Invoke it with:

    SingleTraversalUtilVisitorCallback textVisitor 
        = new SingleTraversalUtilVisitorCallback(
                new TraversalUtilTextVisitor());
    textVisitor.walkJAXBElements(wordMLPackage.getMainDocumentPart().getContents().getBody());

Notes:

  1. if you had <text>this element contains ${var1} and ${var2}</text>, this code would only process ${var1}
  2. if you have variables in your headers/footers, footnotes/endnotes, you'll have to process those parts separately.

Upvotes: 0

Related Questions