We're sorry Aspose doesn't work properply without JavaScript enabled.

Free Support Forum - aspose.com

MailMerge.ExecuteWithRegions throws for specific mergefield/iffield arrangement

Hi,

I’m seeing an odd issue where some mergefields within iffields are throwing an error on document.MailMerge.ExecuteWithRegions, I’ve attached an example. to give a bit of background on the example:

-MockMailMergeDataSourceNoChildren - is just a stand-in for any actual data I might use, as the issue seems to happen no matter what merge data we use
-MailMergePreparer - wraps mergefield with tableStart and tableEnd tags reflecting the main mergefield table - this is actual production logic we use, the merge data we get sent is wrapped in a root tag and we need to reflect that on the document for the mailmerges to correctly find the data for each field in the document
-The mailMerge settings in DoMailMerge reflect our settings from production code

as per the example, this only happens for the mergefield and if structure in the template.dotx file, and not for the templateModified.dotx. As manually going through every template we use and changing the if structure isn’t really possible, I wanted to check if there is something I can do programatically on my side to avoid running into this error? I’m expecting a tweak to the MailMergePreparer would be needed, but can’t really pinpoint where it causes the issue just by looking at the list of nodes and was hoping it would be easier on your side if you could debug into the library code. This seems to be happening on both aspose.words for .net 21.8 (our current production version) and on the latest.

Thanks,
Tomek

mergefieldsExample.zip (38.6 KB)

@acturisaspose The problem occurs because structure of created opening and closing TableStart/TableEnd merge fields is incorrect.
You can fix the problem, by modifying the code like this:

public void PrepareDocument(Document document, IMailMergeDataSource mergeData)
{
    var builder = new DocumentBuilder(document);
    var primaryRecordSetName = mergeData.TableName;
    var documentFields = builder.Document.Range.Fields.ToList();
    foreach (var field in documentFields)
    {
        if (!IsNamedMergefield(field))
        {
            continue;
        }

        var fieldName = ((FieldMergeField)field).FieldName;
        Console.WriteLine(fieldName);

        if (fieldName.StartsWith("TableStart"))
        {
            builder.MoveToField(field, true); // Insert nested table start after TableStart
            builder.InsertField($"MERGEFIELD TableStart:{primaryRecordSetName}");
            continue;
        }
        if (fieldName.StartsWith("TableEnd"))
        {
            builder.MoveToField(field, false); // Insert nested table end before TableEnd
            builder.InsertField($"MERGEFIELD TableEnd:{primaryRecordSetName}");
        }
    }
}

Hi Alexey,

The primaryRecordSet is the outer-most table in our data extracts, which is why we wrap it around all other mergefields - it is not that the primaryRecordSet is nested inside something else, but instead all our data is nested inside primaryRecordSet. I think the mock data set code I sent didn’t really show that, but in our production scenario we have all our data wrapped inside a primaryRecordSetTable and we put the tags around the mergefields in the document so that we can take them from records within the primary record set. Is the description enough or should I update the example project with another implementation of the merge data source that would closer reflect the structure we use in our actual code?

Thanks,
Tomek

@acturisaspose Thank you for additional information. If I understand your requirements properly you need to wrap all your regions into the main region. To achieve this your can use the following code:

private static void PrepareDocument(Document doc, IMailMergeDataSource mergeData)
{
    string primaryRecordSetName = mergeData.TableName;
    DocumentBuilder builder = new DocumentBuilder(doc);

    // Wrap the region hierarchy of the document into top most region.
    MailMergeRegionInfo info = doc.MailMerge.GetRegionsHierarchy();

    // Start the region before the start of the first region.
    builder.MoveToField(info.Regions[0].StartField, false);
    builder.InsertField($"MERGEFIELD TableStart:{primaryRecordSetName}");

    // End the region after the end of the last region.
    builder.MoveToField(info.Regions[^1].EndField, true);
    builder.InsertField($"MERGEFIELD TableEnd:{primaryRecordSetName}");
}