MailMerge Cleanup Options remove "too much"

I have two MailMerge tables, of which one can be empty.
I use
doc.getMailMerge().setCleanupOptions(MailMergeCleanupOptions.REMOVE_UNUSED_REGIONS);
to not render the table at all, if it is empty.

The problem is, the table gets removed, even if not empy.

Template docx:
table-test.docx (66.2 KB)

Result files:
table-test-no-cleanup-two-datasets.pdf (57.9 KB)

table-test-with-cleanup-two-datasets.pdf (57.6 KB)

table-test-with-cleanup-one-datasets.pdf (57.6 KB)

table-test-no-cleanup-one-datasets.pdf (57.8 KB)

Note that “table-test-with-cleanup-two-datasets” contains only one table.

My MailMerge input:

"kontoinhaber-table": [
            {
                "person.lastName": "bb-last",
                "person.firstName": "bb-first",
                "person.domicileAddress.zipCode": "bb-zip",
                "person.domicileAddress.countryName": "bb-country"
            }
        ],
        "drittsicherungsgeber-table": [
            {
                "person.lastName": "cc-last",
                "person.firstName": "cc-first",
                "person.domicileAddress.zipCode": "cc-zip",
                "person.domicileAddress.countryName": "cc-country"
            }
        ]

I use the following code to generate PDFs:

    private void insertMultiTables(Document doc, Map<String, List<Map<String, String>>> tables) throws Exception {

        doc.getMailMerge().setCleanupOptions(MailMergeCleanupOptions.REMOVE_UNUSED_REGIONS);
        long overload = getTableOverload(doc);
        long tableCount = getTableCount(doc);
        long mailMergeRunCount = 0;

        for (Map.Entry<String, List<Map<String, String>>> tableEntry : tables.entrySet()) {

            String tableName = tableEntry.getKey();
            List<Map<String, String>> tableValues = tableEntry.getValue();

            Collection<String> columns = getTableColumns(tableValues);
            DataTable dataTable = new DataTable(tableName);
            columns.forEach(e -> dataTable.getColumns().add(e));

            for (Map<String, String> listEntry : tableValues) {
                dataTable.getRows().add(listEntry.values().toArray());
            }

            for (int i = 0; i < overload; i++) {
                log.debug("Running Mail Merge for table '{}'", tableName);
                doc.getMailMerge().executeWithRegions(dataTable);
                mailMergeRunCount++;
            }

        }

        // trigger cleanup
        // TODO: could be optimized to run only as often as 'totalTableCount' - 'totalMailMergeRunCount'.
        for (int i = 0; i < tableCount; i++) {
            doc.getMailMerge().executeWithRegions(new DataTable());
            mailMergeRunCount++;
        }

        doc.getMailMerge().deleteFields();
    }

@kerner You should put your data tables into data set and fill the whole template with data by executing mail merge with regions once to get the expected output:

DataTable dt1 = getFirstTable();
DataTable dt2 = getSecondTable();
DataSet ds = new DataSet();
ds.getTables().add(dt1);
ds.getTables().add(dt2);
        
Document doc = new Document("C:\\Temp\\in.docx");
doc.getMailMerge().setCleanupOptions(MailMergeCleanupOptions.REMOVE_UNUSED_REGIONS);
doc.getMailMerge().executeWithRegions(ds);
doc.save("C:\\Temp\\out.docx");
1 Like

If I have two tables with the same name, should I execute the whole dataset multiple times or should I only run another Mail Merge for this specific table?

@kerner You should execute mail merge once. You can use MailMerge.MergeDuplicateRegions property to instruct Aspose.Words to fill regions with the same name.

1 Like

Thank you! It works now.

BTW: Is there a possibility to check inside the template if a table is empty? What would be the recommended approach to render a line or paragraph only if a table is not empty?

@kerner You can try using IF field condition in your template.

Tried this already.

{ IF {MERGEFIELD TableStart:tableName} "table present, show some add. info" ""}

Does not work.

{ IF {MERGEFIELD table.columnName} "table present, show some add. info" ""}

I cannot use, because table.columnName also appears in another table.

@kerner You can create a merge field that is filled after filling regions and show or hide empty tables. The merge field value should be calculated in your code:

DataTable dt = new DataTable("Data");
dt.getColumns().add("FirstName");
dt.getColumns().add("LastName");
dt.getColumns().add("Position");
dt.getRows().add("James", "Bond", "Spy");
dt.getRows().add("John", "Dou", "Unknown");

Document doc = new Document("C:\\Temp\\in.docx");
// Fill the region.
doc.getMailMerge().executeWithRegions(dt);
// Fill the mergefield with condition.
// If pass "false" to the test mergefiel the table will be hidden.
doc.getMailMerge().execute(new String[] { "test" }, new String[]{ "true" });
doc.save("C:\\Temp\\out.docx");

in.docx (13.3 KB)
out.docx (10.8 KB)

1 Like

Thank you!

doc.getMailMerge().execute(new String[] { "test" }, new String[]{ "true" });

What is the difference to setting the field as a DocProperty directly via:

doc.getCustomDocumentProperties().add("test", "true");

In this case, I do not need to run a MailMerge. Don’t know if that is better or not.

@kerner You can use the way that is more convenient for you. Both ways will give the same result.

1 Like