Bold Tags Sample & Bug?

I’ve spent more hours than I care to admit getting the code here working and I hope others find it useful. In my datasource some merge fields data has html tags like make this bold. I’m inserting this data into a word document using Aspose’s MailMerge then executing the following code. The problems I had ran into were sometimes the tags were split into different runs. Additionally they could be split into (many) different paragraphs a simple example:

Sign: _______________

John Doe

The following code seems to be working well. I am curious if there is an easier way to do this, I’ve read through the forums for hours and the samples I found didn’t always work when a document had many of these bold tags and especially when tag was split into multiple runs and paragraphs.

One remaining issue I’d like to understand is why I have to call Replace twice to get the twenty-five tag replaced in the attached document i.e.:

Additional trust provisions: If any beneficiary is under the age of twenty-five, or is incapacitated at the time of Grantor’s death, Trustee shall convey his/her property in trust according to the provisions in Exhibit C.

Here’s the code (attached as a file as well) prepping things:

//do these string replaces to fix instances where tags would be in seperate runs due to word revisioning etc 
doc.Range.Replace("", "", false, false);
doc.Range.Replace("", "", false, false);
doc.Range.Replace(new System.Text.RegularExpressions.Regex(@"", System.Text.RegularExpressions.RegexOptions.IgnoreCase), new ReplaceEvaluator(MakeBoldCharByChar), false);
//don’t know why I have to call this again, but sometimes some bold tags aren’t being filled
doc.Range.Replace(new System.Text.RegularExpressions.Regex(@"", System.Text.RegularExpressions.RegexOptions.IgnoreCase), new ReplaceEvaluator(MakeBoldCharByChar), false);

and here’s the overly complicated method to make this text bold in Word:

private static ReplaceAction MakeBoldCharByChar(object sender, ReplaceEvaluatorArgs e)
{
    Run runMatchNode = (Run)e.MatchNode;
    int iBoldStart = runMatchNode.Text.IndexOf("", StringComparison.CurrentCultureIgnoreCase);
    // System.Diagnostics.Debug.WriteLine("run text=’" + runMatchNode.Text + "’");
    if (iBoldStart >= 0)
    {
        int iBoldEnd = runMatchNode.Text.IndexOf("", StringComparison.CurrentCultureIgnoreCase);
        DocumentBuilder builder = new DocumentBuilder(e.MatchNode.Document as Document);
        //Move to Matching Node
        builder.MoveTo(runMatchNode);
        //write content before where bold tag starts
        if (iBoldStart > 0)
        {
            builder.Write(runMatchNode.Text.Substring(0, iBoldStart));
        }
        //bold end tag may not be in this node, if not when inserting html add it, if it is in this node stop inserting html where bold tag ends
        if (iBoldEnd > iBoldStart)
        {
            //end bold tag is in this node
            builder.InsertHtml(runMatchNode.Text.Substring(iBoldStart, iBoldEnd - iBoldStart + 4)); //+ 4 because iBoldEnd is where end bold tag starts and we want to include it so include 4 characters for ""
                                                                                                    //now write out any content after end bold tag (and don’t bold it)
            if (iBoldEnd + 4 < runMatchNode.Text.Length)
            {
                builder.Write(runMatchNode.Text.Substring(iBoldEnd + 4));
            }
            //clear out previous text (we’ve just recreated it)
            runMatchNode.Text = "";
        }
        else
        {
            //end bold tag not in this node, so add it
            builder.InsertHtml(runMatchNode.Text.Substring(iBoldStart) + "");
            //clear out previous text (we’ve just recreated it)
            runMatchNode.Text = "";
            //keep going until end bold tag found
            Node nextNode = runMatchNode.NextSibling;
            if (nextNode == null)
                nextNode = runMatchNode.NextPreOrder(runMatchNode.Document as Document);
            while (nextNode != null)
            {
                builder.MoveTo(nextNode);
                //see if this node contains end bold tag
                iBoldEnd = nextNode.ToTxt().IndexOf("");
                if (iBoldEnd < 0)
                {
                    iBoldEnd = nextNode.ToTxt().IndexOf("");
                }
                if (iBoldEnd < 0)
                {
                    //no end bold tag in this node so make all node text bold
                    if (nextNode.NodeType == NodeType.Paragraph)
                    {
                        Paragraph par = nextNode as Paragraph;
                        foreach (Run runInPar in par.Runs)
                        {
                            runInPar.Font.Bold = true;
                        }
                    }
                    else if (nextNode.NodeType == NodeType.Run)
                    {
                        ((Run)nextNode).Font.Bold = true;
                    }
                    //continue looking for end bold tag
                    nextNode = nextNode.NextSibling;
                    if (nextNode == null)
                        nextNode = nextNode.NextPreOrder(nextNode.Document as Document);
                }
                else
                {
                    //found end bold tag, make text bold up to where end bold tag is
                    builder.InsertHtml("" + nextNode.ToTxt().Substring(0, iBoldEnd + 4)); //+ 4 because iBoldEnd is where end bold tag starts and we want to include it so include 4 characters for ""
                                                                                            //text following end bold tag should not be bold
                    builder.Write(nextNode.ToTxt().Substring(iBoldEnd + 4));
                    //clear out previous text (we’ve just recreated it)
                    nextNode.Remove();
                    //found end bold tag so quit
                    break;
                }
            }
        }
    }
    return ReplaceAction.Skip;
}

Hi

Thanks for your request. If you need to put an HTML into the document upon mail merge, you can easily achieve this using IFieldMergingCallback. You can find a code example here (See the second example):

https://reference.aspose.com/words/net/aspose.words.mailmerging/ifieldmergingcallback/

Hope this helps.

Best regards,

Thank you for the prompt response.

I found the issue with the code above - why I had to call replace twice. It’s because the first match was for the second bold tag and I wasn’t utilizing the position of where the match occurred. Here’s the fixed code (attached as well).

private static ReplaceAction MakeBoldCharByChar(object sender, ReplaceEvaluatorArgs e)
{
    Run runMatchNode = (Run)e.MatchNode;
    int iBoldStart = e.MatchOffset;
    //System.Diagnostics.Debug.WriteLine("run text='" + runMatchNode.Text + "'");

    int iBoldEnd = runMatchNode.Text.IndexOf("", iBoldStart, StringComparison.CurrentCultureIgnoreCase);
    DocumentBuilder builder = new DocumentBuilder(e.MatchNode.Document as Document);
    //Move to Matching Node
    builder.MoveTo(runMatchNode);
    //write content before where bold tag starts
    if (iBoldStart > 0)
    {
        builder.Write(runMatchNode.Text.Substring(0, iBoldStart));
    }
    //bold end tag may not be in this node, if not when inserting html add it, if it is in this node stop inserting html where bold tag ends
    if (iBoldEnd > iBoldStart)
    {
        //end bold tag is in this node
        builder.InsertHtml(runMatchNode.Text.Substring(iBoldStart, iBoldEnd - iBoldStart + 4)); //+ 4 because iBoldEnd is where end bold tag starts and we want to include it so include 4 characters for ""
                                                                                                //now write out any content after end bold tag (and don't bold it)
        if (iBoldEnd + 4 < runMatchNode.Text.Length)
        {
            builder.Write(runMatchNode.Text.Substring(iBoldEnd + 4));
        }

        //clear out previous text (we've just recreated it)
        runMatchNode.Text = "";
    }
    else
    {
        //end bold tag not in this node, so add it
        builder.InsertHtml(runMatchNode.Text.Substring(iBoldStart) + "");

        //clear out previous text (we've just recreated it)
        runMatchNode.Text = "";

        //keep going until end bold tag found
        Node nextNode = runMatchNode.NextSibling;
        if (nextNode == null)
            nextNode = runMatchNode.NextPreOrder(runMatchNode.Document as Document);
        while (nextNode != null)
        {
            builder.MoveTo(nextNode);
            //see if this node contains end bold tag
            iBoldEnd = nextNode.ToTxt().IndexOf("");
            if (iBoldEnd < 0)
            {
                iBoldEnd = nextNode.ToTxt().IndexOf("");
            }
            if (iBoldEnd < 0)
            {
                //no end bold tag in this node so make all node text bold
                if (nextNode.NodeType == NodeType.Paragraph)
                {
                    Paragraph par = nextNode as Paragraph;
                    foreach (Run runInPar in par.Runs)
                    {
                        runInPar.Font.Bold = true;
                    }
                }
                else if (nextNode.NodeType == NodeType.Run)
                {
                    ((Run)nextNode).Font.Bold = true;
                }

                //continue looking for end bold tag
                nextNode = nextNode.NextSibling;
                if (nextNode == null)
                    nextNode = nextNode.NextPreOrder(nextNode.Document as Document);
            }
            else
            {
                //found end bold tag, make text bold up to where end bold tag is
                builder.InsertHtml("**" + nextNode.ToTxt().Substring(0, iBoldEnd + 4)); //+ 4 because iBoldEnd is where end bold tag starts and we want to include it so include 4 characters for "**"
                                                                                        //text following end bold tag should not be bold
                builder.Write(nextNode.ToTxt().Substring(iBoldEnd + 4));

                //clear out previous text (we've just recreated it)
                nextNode.Remove();

                //found end bold tag so quit
                break;
            }
        }
    }

    return ReplaceAction.Skip;
}

Hi Chad,

Thank you for additional information. Have you tried using the suggested approach with IFieldMerginfCallback and InsertHtml method? I think, you can achieve exactly the same using this approach and it is simpler than your approach (i.e. less error prone).

Best regards,

I have and it’s MUCH EASIER. I had done manipulations for images, like that, but hadn’t thought of doing it for fields. However it is mucking up my layout (perhaps if I spent some time on it playing with the HTML I could work around that), in particular at one point it’s Justifying the text so it fills the width of the document, when there’s 5 words at the end of paragraphs it looks really odd. My text I’m inserting only has bold, italics, and (maybe) underline tags so I’m not sure why that is happening.

I haven’t really worried about it as I finally got the code posted above working and it keeps the formatting of the original layout just fine. I’ll certainly be using the method you shared in the future though (maybe I just need to upgrade my version too, as the method I tested has a different name (I’m out of date) but still seems like it would work if figuring out the layout issue).

Hi Chad,

Thanks for your inquiry.

If you are using an old version most likely that unexpected behaviour is a bug which would of been fixed in a later version .Please try using the latest version of Aspose.Words for testing and let us know if there are any issues.

Thanks,