Can IMailMergeDataSource be used for both plain and region mail merge at once?

Hi,

I am experimenting with Aspose.Words trying to create a document merging engine.

The idea is the following:
- engine gets info in JSON format
- info includes: document to load as template, data to fill in, path where to save the document

To perform the mail merge in the engine, I tried implementing a custom class which implements IMailMergeDataSource and internally it is structured as a HashMap of keys => values, where values can be a plain string (for “simple” mail merge), or an instance of another class, which also implements IMailMergeDataSource (for “region” mail merge).

The problem is, when I instantiate the root class, and then call

doc.getMailMerge().execute(data);

and then save the document, I see that no merge has been done at all.

I am attaching the template I am using for testing and here follows the class code:

private static class Merge implements IMailMergeDataSource {
private HashMap<String, Object> values = new HashMap<>();

public Merge(JsonObject data) throws Exception {
Iterator keys = data.keys();
while (keys.hasNext()) {
String k = keys.next().toString();
Object v = data.get(k);

if (v instanceof JsonArray) {
System.out.println("Merge: caricata tabella " + k);
values.put(k, new Table(k, (JsonArray) v));
}
else {
System.out.println("Merge: caricata stringa " + k + ", valore " + v.toString());
values.put(k, v.toString());
}
}

System.out.println("Merge: caricati valori: " + values.toString());
}

@Override
public String getTableName() throws Exception {
return “”;
}

@Override
public boolean moveNext() throws Exception {
return false;
}

@Override
public boolean getValue(String s, Object[] objects) throws Exception {
try {
objects[0] = values.get(s).toString();
return true;
}
catch (Exception e) {
objects[0] = null;
}

System.out.println("Merge: getValue " + s + ", value " + objects[0]);
return false;
}

@Override
public IMailMergeDataSource getChildDataSource(String s) throws Exception {
System.out.println("Merge: getChildDataSource " + s);
try {
return (Table) values.get(s);
}
catch (Exception e) {
return null;
}
}

private static class Table implements IMailMergeDataSource {
private ArrayList rows;
private String name = “”;
private int current = 0;

public Table(String name, JsonArray rows) throws Exception {
int length = rows.length();

this.name = name;
this.rows = new ArrayList(length);

for (int i = 0; i < rows.length(); ++i) {
System.out.println("Table: caricata riga " + i);
JsonObject v = rows.getJSONObject(i);
this.rows.add(new Merge(v));
}
}

@Override
public String getTableName() throws Exception {
return name;
}

private boolean isEot() {
return current >= rows.size();
}

@Override
public boolean moveNext() throws Exception {
if (!isEot()) {
++current;
}

return !isEot();
}

private Merge current() {
return rows.get(current);
}

@Override
public boolean getValue(String s, Object[] objects) throws Exception {
System.out.println("Table: getValue " + s);
return current().getValue(s, objects);
}

@Override
public IMailMergeDataSource getChildDataSource(String s) throws Exception {
System.out.println("Table: getChildDataSource " + s);
return current().getChildDataSource(s);
}
}
}

Can you help me with this?

Hi Matteo,


Thanks for your inquiry. You need to separately call both ExecuteWithRegions and Execute methods as they do very different things. Please note that ExecuteWithRegions method fills a region in the document defined by a pair of matching TableStart and TableEnd merge fields with the same table name while the Execute method performs a standard mail merge. You should run ExecuteWithRegions first and then run Execute method after it. I hope, this helps.

Best regards,