Change in merge field after (finally) upgrading to most recent version

For particular reasons, we’ve held off from upgrading our version on Aspose.Words in a particular application until this year. Currently the version is 17.12 and it handles what the users call “Frankenlinks” just fine. However, after upgrading to 23.3, the merge fields no longer render as they did. Doing a bit of research, it looks like the change happened in 18.7; any version I’ve tried greater than or equal to it has the issue.

I’ve attached the source document and the resulting documents using 17.12 and 23.3, plus the script I’m using to test.

Frankenlink.docx (31.5 KB)
Frankenlink_2017.docx (27.2 KB)
Frankenlink_2023.docx (27.2 KB) (959 Bytes)

@joe_lopez Thank you for reporting the problem to us, the current version of Aspose.Words breaks hyperlink with nested hyperlink field.
We have opened the following new ticket(s) in our internal issue tracking system and will deliver their fixes according to the terms mentioned in Free Support Policies.

Issue ID(s): WORDSNET-25136

You can obtain Paid Support Services if you need support on a priority basis, along with the direct access to our Paid Support management team.

As a workaround, you can check whether merge field is nested into a hyperlink field and insert simple text in this case. I have modified your code so it produces the correct output:

Document doc = new Document(@"C:\Temp\in.docx");

// Fix field names (enclose field names with whitespaces into double quotes)

var fieldNames = new string[] { "S innovation plan URL" };
var fieldValues = new string[] { "" };

doc.MailMerge.FieldMergingCallback = new HandleMailMergeEvents();
doc.MailMerge.Execute(fieldNames, fieldValues);

private static void FixFieldNames(Document doc)
    List<Field> mergefields = doc.Range.Fields.Where(f => f.Type == FieldType.FieldMergeField).ToList();

    DocumentBuilder builder = new DocumentBuilder(doc);

    foreach (Field field in mergefields)
        Regex regex = new Regex(MERGE_FIELD_REGEX);
        Match match = regex.Match(field.GetFieldCode());
        string resultFieldCode = string.Format("MERGEFIELD \"{0}\" \\* MERGEFORMAT", match.Groups["fieldName"].Value);
        // Move document buidler cursor to the mergefield and insert the corrected mergefield.
        builder.MoveToField(field, false);
        Field newField = builder.InsertField(resultFieldCode);
        // remove old mergefield.

const string MERGE_FIELD_REGEX = @"MERGEFIELD (?<fieldName>.+) \\\* MERGEFORMAT";

private class HandleMailMergeEvents : IFieldMergingCallback
    void IFieldMergingCallback.FieldMerging(FieldMergingArgs e)
        var fillInText = e.FieldValue.ToString();
        // Simple check whether the value is URL. More advanced condition can be used instead
        if (fillInText.StartsWith("http"))
            // Check if the mergefield is nested into the hyperlink field.
            bool isNestedInHyperlink = false;
            Node currentNode = e.Field.Start.PreviousSibling;
            while (currentNode != null)
                if (currentNode.NodeType == NodeType.FieldStart)
                    isNestedInHyperlink = ((FieldStart)currentNode).FieldType == FieldType.FieldHyperlink;
                currentNode = currentNode.PreviousSibling;

            if (!isNestedInHyperlink)
                DocumentBuilder builder = new DocumentBuilder(e.Document);
                // Move cursor to the field and insert hyperlink.
                builder.MoveToField(e.Field, false);
                builder.InsertHyperlink(fillInText, fillInText, false);
                e.Text = "";

    void IFieldMergingCallback.ImageFieldMerging(ImageFieldMergingArgs args)

First of all, thank you not only for the quick response but the code sample. As always, Aspose tech support is exemplary.

In our app, there’s a preliminary step which removes custom properties/macros and saves the input doc. The sample document I sent you didn’t go through this step. Since it doesn’t have anything to do with merge fields, I didn’t suspect it had any impact, but when I implemented your workaround in the app I kept getting unexpected results. When I included the preliminary step in my testing, I saw that it had changed the nested hyperlink field. Then I commented out everything but the save, and I realized that simply opening and then saving a document alters the field and breaks the workaround (files attached):

Document doc = new Document(@"C:\Temp\in.docx");

If I use the resulting document as the input to the workaround, it no longer works. For now, I’ve rearranged the app code a bit to include the custom properties/macros removal as part of the workaround and all is well. Thanks again. (50.2 KB)

@joe_lopez Yes, you are right, simple open/save breaks the fields nested into HYPERLINK field. I have updated WORDSNET-25136 appropriately. We will keep you posted and let you know once the issue is resolved or we have more information for you.

The issues you have found earlier (filed as WORDSNET-25136) have been fixed in this Aspose.Words for .NET 23.5 update also available on NuGet.