Free Support Forum - aspose.com

Replacing Mail Merge Fields

Hi,

I am trying to replace some code that currently uses Word Automation, and have been testing Aspose.Words for .Net. Part of the existing application utilises Mail Merge, and I have been able to replicate that piece using Aspose.Words. However, before the Mail Merge runs, there is also some code which loops through all of the Mail Merge fields, tests to see whether or not they exist within the Mail Merge database table, and if not it searches some other database tables, and (if it finds the field names in these database tables) it replaces the Mail Merge field with the database value. It's like a manual pre-merge before the proper merge. I know this probably sounds a bit odd, but it does make sense within the context of the existing application!

I have been able to write the Aspose.Words code to a point whereby the Mail Merge is working, and the other code which looks at additional database tables is also almost working. However, I have run into a problem that I need some advice on.

In order to loop around the Mail Merge fields, I have written the following code:

Dim Collection As Aspose.Words.NodeCollection
Dim start As Aspose.Words.FieldStart

Dim CurrentNode As Aspose.Words.Node

Collection = TableCell.GetChildNodes(Aspose.Words.NodeType.FieldStart, True)

For Each start In Collection

If start.FieldType = Aspose.Words.FieldType.FieldMergeField Then
CurrentNode = start
While CurrentNode.NodeType <> Aspose.Words.NodeType.FieldSeparator
CurrentNode = CurrentNode.NextSibling
If CurrentNode.NodeType = Aspose.Words.NodeType.Run Then FieldName = FieldName + CurrentNode.ToTxt
End While
FieldName = FieldName.Replace("MERGEFIELD", "") 'remove "MERGEFIELD" from FieldName
FieldName = FieldName.Replace("""", "") 'remove quotes from FieldName
If FieldName.IndexOf("\") > 0 Then FieldName = FieldName.Substring(0, FieldName.IndexOf("\")).Trim 'remove any trailing items (Word formatting) from FieldName
End If
Next

This allows me to loop through each Merge Field in turn, and is working correctly. I have then written some code that looks at the FieldName value, and if it is a field that needs to be replaced, calls a routine which (1) steps back through each PreviousSibling of CurrentNode until it finds FieldStart, and then (b) removes each NextSibling until it reaches FieldEnd. This allows the whole Field to be deleted - and this too is working correctly.

The problem I am having is that in the first piece of code, the line "For Each start In Collection" is getting confused. Let's say that the first time the For loop is executed it finds 2 Mail Merge fields. The first time through the loop the first Mail Merge field will be replaced correctly. However, when the code gets to the Next statement, there is now only 1 Mail Merge node, and so the loop exits (without processing the second Mail Merge field).

I have tried re-writing this code several different ways, but I'm wondering whether I am missing something. Is there an easier way to loop through each of the Mail Merge fields, and replace those that need replacing with plain text?

Thanks

Hi

Thanks for your request. It seems that code above is used only for getting names of mergfields, right? I think that you can use the following code line to get field names and then loop through through each Merge Field name.

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

If you would like to remove MergeField then you can use the following line:

builder.MoveToMergeField(fieldName);

I hope this could help you.

Best regards.

Hi Alexey,

I have had a look at this, but it hasn't really helped me. The MailMerge.GetFieldNames command gets all the field names in the document, but I only need to delete certain fields based on certain conditions. The fields I am trying to replace will always be in Word tables. The original (Word Automation) code simply steps through each cell within each table (and each embedded "nested" table within any of those cells) and checks each mail merge field it finds. If the mail merge field needs to be replaced, the code simply replaces the field with some text, and continues.

With Aspose.Words, I have almost been able to reproduce this functionality, but my problem is really with the "For Each FieldStart in Cell.GetChildNodes(Aspose.Words.NodeType.FieldStart, True)" line. Whilst this is able to loop through each field in the cell, it goes wrong if any field is deleted. I don't think the MailMerge.GetFieldNames helps, either, because this doesn't allow me to limit the fields to those in the current cell.

Thanks for your help. It's much appreciated

Hi

Thanks for additional information. I think that you can try using the following code.

ArrayList list = new ArrayList();

NodeCollection starts = doc.GetChildNodes(NodeType.FieldStart, true);

foreach (FieldStart start in starts)

{

//*****here is your conditional logic

list.Add(start);

}

foreach (FieldStart start in list)

{

//Remove field

}

Best regards.

This looks really hopeful. Thanks again Alexey

Hi Alexey,

I have now got the code working pretty well. There is just one problem. When I delete the old mail merge field and insert the new text, I am losing the formatting (font and colour) of the mail merge field. Is there a way I can retain the formatting? The code to replace the mail merge field with the new text is as follows:

Do

If CurrentNode.NodeType = Aspose.Words.NodeType.FieldStart Then

Do

ExitLoop = True

If CurrentNode.NodeType = Aspose.Words.NodeType.FieldEnd Then

Dim Run As Aspose.Words.Run = New Aspose.Words.Run(CurrentNode.Document, NewText)

CurrentNode.ParentNode.InsertAfter(Run, CurrentNode)

CurrentNode.Remove()

CurrentNode = CurrentNode.PreviousSibling

Exit Do

Else

CurrentNode = CurrentNode.NextSibling

CurrentNode.PreviousSibling.Remove()

End If

Loop

Else

CurrentNode = CurrentNode.PreviousSibling

End If

Loop Until ExitLoop = True

Hi

Thanks for your inquiry. FieldEnd has property Font. So you can get font formationg from this property. For example

If CurrentNode.NodeType = Aspose.Words.NodeType.FieldEnd Then

Dim Run As Aspose.Words.Run = New Aspose.Words.Run(CurrentNode.Document, NewText)

CurrentNode.ParentNode.InsertAfter(Run, CurrentNode)

Dim fieldEnd As Fields.FieldEnd = CType(CurrentNode, Fields.FieldEnd)

Run.Font.Size = fieldEnd.Font.Size

CurrentNode.Remove()

CurrentNode = CurrentNode.PreviousSibling

Exit Do

Else

CurrentNode = CurrentNode.NextSibling

CurrentNode.PreviousSibling.Remove()

End If

I hope this could help you.

Best regards.