How to make all the merge fields merged

Hi Support,

I am building a PDF template validation tool, which uses a predefined data set to merge the PDF template provided by our customer to find potential template errors. I would like to know a way to merge all the merge fields in the template with my data set.

Currently I am facing the following issue with Aspose.words 17.4. I have one IF expression,
{IF «Account.Currency» = USD «Invoice.InvoiceNumber» «Account.Name»}.
In my datasource provided, all the values for Account.Currency, Invoice.InvoiceNumber, Account.Name are there, but because Aspose only merges the merge fields which conforms to the IF condition, so only «Invoice.InvoiceNumber» is merged with my data set. This behavior makes the «Account.Name» miss the validation.

With Aspose 15.2 and with the same data set, all the merge fields can be merged no matter if it conforms to the IF condition, that behavior is I expect. How can I achieve that with Aspose.word 17.4?

Thanks
Tony Shen

@stlcn

Thanks for your inquiry. We have already addressed your same query. It is not a bug but we have changed Aspose.Words Mail Merge feature in later version of Aspose.Words to mimic MS Word Mail Merge behavior. You can refer your old post for details and suggested solution.

Hi Tilal,

Thanks for help again. There is some difference comparing with my previous query. I used a composite data source this time, all the values that are necessary for the IF expression are provided by the datasource. So I would like to know if it is possible to merge all the merge fields in the IF expression, namely both «Invoice.InvoiceNumber» and «Account.Name» are merged.

If the «Account.Name» can’t be merged, can it be removed from the IF expression? I tried with MailMergeCleanupOptions.REMOVE_UNUSED_FIELDS, but it failed to remove, the merge result is like below,
{IF USD = USD INV-000001 «Account.Name»}.
What is wrong with my settings? The following is the code.

doc.getMailMerge().setCleanupOptions(MailMergeCleanupOptions.REMOVE_UNUSED_FIELDS);
doc.getMailMerge().execute(getDatasourceTwo());
doc.getMailMerge().getFieldNames();//Return the unmerged fields.
doc.save("IFCondition2_17.4.doc", SaveFormat.DOC);

In a summary, our requirement is no matter where the merge fields exist they should be merged. If there are any fields that are not merged we look the document as an wrong document. Do you have any solution?

Thanks
Tony

@stlcn

Thanks for your feedback. You mean as suggested in other post you have combined the Invoice and account values in a single datasource. Please share following resources here, we will look into the issue and will guide you accordingly.

  • Input Word template
  • Output document with Aspose.Words for Java 17.8
  • Expected Word output, you can create it using MS Word.
  • Data source
  • Sample code(without compilation error)

@tilal.ahmad

Please find the attached for the template as well as the code for demonstrating the issue.to aspose.zip (19.3 KB)

The following is our use scenarios.

  1. During uploading a PDF template, we would like to validate if the template is defined correctly, so we merge the template with predefined data set, and we expect each field is merged to make sure it is defined correctly. In this scenario, the part which doesn’t conform to “if condition” is not merged even we can provide the value in the datasource, which means this field is not validated.
  2. During PDF generation, we need to check if all the fields that need to be merged are merged. It is not acceptable we send out a final PDF with unmerged fields. We are calling MailMerge.getFieldNames() to check if there are any fields that are not got merged. This method always returns the field which doesn’t conform to the “if condition”, so we can’t make the judgement if the final PDF is fully merged.

For #1 scenario, we expect all the fields are merged no matter where they are located;
For #2 scenario, we expect a way to get all the fields which need to be merged but not.

Any more questions please let me know.

Thanks
Tony

@stlcn

Thanks for sharing the additional information. Please note in case of IF condition, Aspose.Words mimics MS Word behavior. It only merges the field that meets the IF condition and leave other field intact. So to remove all un-merged fields from IF statement you can use REMOVE_CONTAINING_FIELDS value of MailMergeCleanupOptions. Please check following sample code snippet, it will help you to accomplish the task.

Document doc = new Document("remaining_field_template.doc");
doc.getMailMerge().setCleanupOptions(MailMergeCleanupOptions.REMOVE_CONTAINING_FIELDS | MailMergeCleanupOptions.REMOVE_UNUSED_FIELDS);
doc.getMailMerge().execute(new String[] { "Invoice.InvoiceNumber", "Account.Currency", "Account.Name" }, new Object[] { "INV-000001","USD","Zuora"});
doc.save("IFCondition_178.doc", com.aspose.words.SaveFormat.DOC);

@tilal.ahmad

Thanks for the quick response.
Removing the unmerged fields can’t meet our requirement exactly after thinking further.
For #1, we would like all the fields are merged with our predefined data for the validation. If the unmerged fields are removed during validation, that means they are not validated. When real data are provided to this template those fields may fail to be merged for potential definition mistakes;
For #2, we can’t remove the unmerged fields, especially with the MailMergeCleanupOptions.REMOVE_UNUSED_FIELDS. There are two reasons, one reason is we also provide the merged Word document to our customers. Removing the IF condition means a behavior change to our customer. The other reason is more critical, if there are unmerged fields outside of IF expression, we don’t know why it is not merged. In this situation, we would like to report an error to block generating the final PDF instead of removing those unmerged fields with REMOVE_UNUSED_FIELDS options. After we do some investigation to know the reason why the PDF is not generated, we can help customers to regenerated the PDF. Sending customers a PDF late is much better than sending them a wrong one.

As I explained in the previous post, our requirements are
For #1 scenario, we expect all the fields are merged no matter where they are located, so each field is validated with our predefined data;
For #2 scenario, we expect a way to get all the fields which need to be merged but not. namely, the fields that don’t meet IF condition should be excluded;

Are our use scenarios and requirements clear enough to you?
I understand your current IF behavior well, but we implemented our function based on Aspose.words heavily, I hope you could provide a solution to meet our requirements.

Any more question please let me know.

Thanks
Tony

@stlcn

Thanks for your feedback. In reference to remaining_field_expect_result_17.8.doc, it is your expected document. Please share some details with screenshots how you created this document using MS Word. We will share our findings accordingly.

@tilal.ahmad remaining_field_expect_result_17.8.doc is my expected document after merging. In this document we can see each field was merged, even if the field is on the FALSE branch of the IF expression.

The following screenshots show me how this document was created.

  1. Run my test code to generate the a merged MS Words document, as shown by Screen Shot - before.png (14.8 KB);
  2. Deleted the unmerged field “Account.Name”, as shown by Screen Shot - delete.png (14.5 KB);
  3. Input the expected value “Zuora”, as shown by Screen Shot --input.png (12.9 KB);
  4. Got the final document, as shown by Screen Shot – final.png (12.4 KB);

Any more questions please let me know.

It is very appreciated you can help on this.

Tony Shen

@stlcn

Thanks for sharing the additional information. You may use following code to accomplish your first scenario. For second scenario you can get MailMerge fields from your resultant document and compare with FalseText/TrueText properties of FieldIf. Hopefully it will help you to accomplish the task.

Document doc = new Document("remaining_field_template.doc");

//doc.MailMerge.CleanupOptions = (MailMergeCleanupOptions.RemoveUnusedRegions | MailMergeCleanupOptions.RemoveUnusedFields | MailMergeCleanupOptions.RemoveContainingFields);
doc.MailMerge.Execute(new string[] { "Invoice.InvoiceNumber", "Account.Currency", "Account.Name" }, new object[] { "INV-000001","USD","Zuora"});

DocumentBuilder builder= new DocumentBuilder(doc);
           
string[] remainingMergeFields = doc.MailMerge.GetFieldNames();

foreach (string fieldName in remainingMergeFields)
{
    builder.MoveToMergeField(fieldName);

    if (fieldName.Contains("Account.Name"))
    {
    builder.Write("Zuora");
    }

}

doc.Save("IFCondition_178.doc", SaveFormat.Doc);

@tilal.ahmad

Thanks a lot for the solution of the first scenarios. I tried it briefly and I think it should resolve my issue.
For the second scenario, I don’t know how I can get the FieldIf instance, can you give more instruction?

I am also thinking about using the same way of scenario 1 to fix the issue of scenario 2. After the auto mail merge process, I will move to each unmerged field and try to get the value from the composite datasource and merge the field. If the value is in the composite datasource, then it can be merged. After this process if there still are some unmerged fields, then I can report an error. Do you see any potential issues in this way for scenario 2?

Thanks
Tony Shen

@stlcn

Thanks for your feedback. It is good to know that shared solution worked for you. Your solution for second scenario seems fine to know if you have still any field that left after manual merging the fields.

However, to know after mail merge process that whether a merge field is part of IF condition or not you can use FieldIf field as following. You can customize/improve as per your need.

Document doc = new Document(@"D:\Downloads\to aspose\to aspose\remaining_field_template.doc");
//doc.MailMerge.CleanupOptions = (MailMergeCleanupOptions.RemoveUnusedRegions | MailMergeCleanupOptions.RemoveUnusedFields | MailMergeCleanupOptions.RemoveContainingFields);
doc.MailMerge.Execute(new string[] { "Invoice.InvoiceNumber", "Account.Currency", "Account.Name" },
new object[] { "INV-000001","USD","Zuora"});
DocumentBuilder builder= new DocumentBuilder(doc);
String IFResults =null;
foreach (Field field in doc.Range.Fields)
{
if (field.Type == FieldType.FieldIf)
{
    FieldIf fieldIf = (FieldIf)field;
    IFResults=  IFResults+fieldIf.FalseText+",";
    IFResults = IFResults + fieldIf.TrueText + ",";
}
}

string[] remainingMergeFields = doc.MailMerge.GetFieldNames();

foreach (string fieldName in remainingMergeFields)
{
if (IFResults.Contains(fieldName))
Console.WriteLine(fieldName+" is part of IF Condition");
// Customize as per requirements
}
....

@tilal.ahmad

I tried some complexity cases today, unfortunately the solution for scenario 1 does not work this time. I tried the following merge field which has custom format.
{MERGEFIELD Account.Amount \# ###,###,###,#00.0000}

If the Account.Amount is 10, and it is merged, then the final result is 10.0000. But If I used builder.Write(“10”), it is displayed as 10. Which means, I couldn’t validate the format defined.

So I have to give up this solution.

I tried to get the FieldIf with the way you showed me, it works with some simple cases with my scenario 2. I will continue working on some complex ones.

Thanks
Tony Shen

@stlcn

I am afraid while merging fields manually you have to face the issues. However please share your sample template, we will look into it and will guide you accordingly.

@tilal.ahmad

The attached is the template with formatted number. number_field_with_format_template.doc.zip (7.5 KB)

Thanks for helping on this.

Tony Shen

@tilal.ahmad

I tried the complex scenario 2 with the FieldIf. Unfortunately, the FieldIf doesn’t help. For example, I have the following IF expression, remaining_field_template_multiIf.doc.zip (7.8 KB)
And the merge result is remaining_field_template_multiIf_result_17.8.doc.zip (4.5 KB)

Though I could get the True tex, False text for each IF expression, but I couldn’t differentiate which merge field should be merged but not.

Thanks
Tony Shen

@stlcn

Thanks for your feedback. Please share your document with actual scenario along with sample data. We will look into it and will try to provide you solution accordingly.

@tilal.ahmad
The attached is a real doc template from one of our customersXplornetInvoiceTemplate.doc.zip (15.1 KB)
. You can find the merge fields with custom format in it. For example, Account.PreviousBalance, Invoice.Total. The backend data is too complex to provide. But I think you can use my previous template(number_field_with_format_template.doc) to do the investigation, which is simple.

Thanks a lot for you help.

Tony Shen

@stlcn

Thanks for sharing the sample document. We are working on your query and will update you soon.

@stlcn

Thanks for your patience. Please check following updated code snippet for scenario 1. You can further customize the code as per your need.

For scenario 2, please share your sample data and code used for above shared template.

Document doc = new Document(@"remaining_field_template.doc");
doc.MailMerge.Execute(new string[] { "Invoice.InvoiceNumber", "Account.Currency", "Account.Name" },
    new object[] { "INV-000001", "USD", "10" });

DocumentBuilder builder = new DocumentBuilder(doc);

foreach (Field field in doc.Range.Fields)
{
    if (field.Type == FieldType.FieldMergeField)
    {
        if (field.GetFieldCode().Contains("Account.Name"))
        {
            String account = "10";
            builder.MoveToField(field, false);
            builder.StartBookmark("bm");
            builder.MoveToField(field, true);
            builder.EndBookmark("bm");
            //add value with mail merge format
            if (field.GetFieldCode().LastIndexOf("\\") > 0)
            {
                int intvalue;
                bool parsed = int.TryParse(account, out intvalue);
                if (parsed)
                {
                    builder.Write(intvalue.ToString(field.GetFieldCode().Substring(field.GetFieldCode().LastIndexOf("\\") + 3)));
                    Bookmark bookmark = doc.Range.Bookmarks["bm"];
                    bookmark.Text = "";
                    bookmark.Remove();
                }
                else
                    Console.WriteLine("invalid number");
            }
            else
            {
                builder.Write(account);
                Bookmark bookmark = doc.Range.Bookmarks["bm"];
                bookmark.Text = "";
                bookmark.Remove();
            }

        }

    }
}
doc.Save(@"IFCondition_179_account.doc", SaveFormat.Doc);