Aspose MailMerge with word

Hello,

We have been using aspose mailmerge with word templates. Attached the sample input, code, template and the output pdf. The input is in the form of a json. We are using aspose version 22.8 with java.

We now have a requirement for cascading tables where one table has multiple tables in it. We have attached a sample report. Defendant is a table and each defendant will have multiple tables. We have looked into aspose website and see that it can be achieved with xml structure. Can we do that with what we currently have? Can we extend our current program to generate the document as per new requirement. Please advise.

Input_Json.docx (13.9 KB)
Code.docx (18.5 KB)
TestTemplate.docx (16.7 KB)
GeneratedFromTemplate.pdf (62.4 KB)
New Requirement Sample.docx (247.4 KB)

@judiciary What you are asking about is called Nested Mail Merge with Regions. You are right when you use XML data source, the relations between the table are build automatically while reading XML data into DataSet. In your case you should create relations yourself. For example see the following simple example:

// Define data set and data tables
DataSet ds = new DataSet();
DataTable root = new DataTable("root");
root.getColumns().add("id");
root.getColumns().add("title");
DataTable child = new DataTable("child");
child.getColumns().add("root_id");
child.getColumns().add("value");

// Add tables into the data set
ds.getTables().add(root);
ds.getTables().add(child);
// Define relation between the tables.
ds.getRelations().add(root.getColumns().get("id"), child.getColumns().get("root_id"));

// Put some dummy data into the tables.
// In your case data will be read from JSON.
root.getRows().add(1, "First Group");
root.getRows().add(2, "Second Group");
root.getRows().add(3, "Third Group");
child.getRows().add(1, "First item in the First Group");
child.getRows().add(1, "Second item in the First Group");
child.getRows().add(1, "Third item in the First Group");
child.getRows().add(2, "First item in the Second Group");
child.getRows().add(2, "Second item in the Second Group");
child.getRows().add(3, "Lonely item in the Third Group");

// Open template and execute mail merge with regions.
Document doc = new Document("C:\\Temp\\in.docx");
doc.getMailMerge().executeWithRegions(ds);
doc.save("C:\\Temp\\out.docx");

in.docx (13.9 KB)
out.docx (11.4 KB)

Alternatively, you can use implement IMailMergeDataSource and the appropriate getChildDataSource method to return data source for the child region.

Thank you for the response. We were looking into the xml option at the below article. However, we could not locate the word template referred in this example on github. Will you be able to provide that?

Is there an example to implement nested tables with xml input

Mail Merge with XML Data Source in Java|Aspose.Words for Java

@judiciary Here is code example, data and template:

DataSet customersDs = new DataSet();
customersDs.readXml(getMyDir() + "Mail merge data - Customers.xml");

Document doc = new Document(getMyDir() + "Mail merge destinations - Registration complete.docx");
doc.getMailMerge().execute(customersDs.getTables().get("Customer"));

doc.save(getArtifactsDir() + "WorkingWithXmlData.XmlMailMerge.docx");

data+template_mailmerge_from_xml.zip (11.8 KB)

Here is an example data and template for nested mail merge with regions using XML data source:

DataSet pizzaDs = new DataSet();
pizzaDs.readXml(getMyDir() + "Mail merge data - Orders.xml");
        
Document doc = new Document(getMyDir() + "Mail merge destinations - Invoice.docx");

// Trim trailing and leading whitespaces mail merge values.
doc.getMailMerge().setTrimWhitespaces(false);

doc.getMailMerge().executeWithRegions(pizzaDs);

doc.save(getArtifactsDir() + "WorkingWithXmlData.NestedMailMerge.docx");

data+template_nested_mailmerge_from_xml.zip.zip (55.4 KB)

You can find the corresponding examples on our github, templates and data are here.

Hi,

We are trying to generate pdf using word template with mailmerge and xml as an input. If there is no data in a certain table or row we want that row to be not displayed when the pdf is generated. In the attached template, when there is no data for Review table, it completely skips that row. However, when there is no data for ndf and total fileds we see an empty row in the generated output. We even tried changing ndf to a table to see if that works but that did not help. Below are the cleanup options we have set. Please advise.

doc.getMailMerge().setCleanupOptions(MailMergeCleanupOptions.REMOVE_UNUSED_REGIONS | MailMergeCleanupOptions.REMOVE_UNUSED_FIELDS 
    | MailMergeCleanupOptions.REMOVE_EMPTY_PARAGRAPHS | MailMergeCleanupOptions.REMOVE_CONTAINING_FIELDS |
    MailMergeCleanupOptions.REMOVE_EMPTY_TABLE_ROWS);

Test.zip (33.6 KB)

@judiciary The behavior is expected. The first row in the Review has one cell where TableStart and TableEnd fields are located. In this case the paragraph is considered as as a region, not the whole row. So REMOVE_EMPTY_TABLE_ROWS does not affect this row and REMOVE_UNUSED_REGIONS removes only the empty paragraph from the cell, the row remains.
The last row of this table is not affected by REMOVE_EMPTY_TABLE_ROWS because this option works only if the row is the region, i.e. TableStart and TableEnd fields are in the same row. In your case the row is only part of the region.
I am afraid there is no way to cover such cases using MailMergeCleanupOptions. To achieve what you need it is required to postprocess the document after executing mail merge. For example see the following code:

DataSet ds = new DataSet();
ds.readXml("C:\\Temp\\in.xml");

Document doc = new Document("C:\\Temp\\in.docx");
doc.getMailMerge().setCleanupOptions(
        MailMergeCleanupOptions.REMOVE_UNUSED_REGIONS
        | MailMergeCleanupOptions.REMOVE_UNUSED_FIELDS
        | MailMergeCleanupOptions.REMOVE_EMPTY_PARAGRAPHS
        | MailMergeCleanupOptions.REMOVE_CONTAINING_FIELDS
        | MailMergeCleanupOptions.REMOVE_EMPTY_TABLE_ROWS);

doc.getMailMerge().executeWithRegions(ds);

// Remove empty rows from the tables.
Iterable<Table> tables = doc.getChildNodes(NodeType.TABLE, true);
for (Table t : tables)
{
    // Consider row as empty if it does not have any RUN nodes.
    while (t.getLastRow() != null
            && t.getLastRow().getChildNodes(NodeType.RUN, true).getCount() == 0)
    {
        t.getLastRow().remove();
    }
}

doc.save("C:\\Temp\\out.pdf");

out.pdf (23.9 KB)

If you need to remove the header row of an empty table, you can add an additional condition to remove tables with only one remaining row.