How to perform mail merge in Word with XML data containing HTML tags in C#?
Syncfusion® Essential® DocIO is a .NET Word library used to create, read, edit, and convert Word documents programmatically without Microsoft Word or interop dependencies. Using this library, you can perform mail merge in Word with XML data containing HTML tags using C#.
To achieve this, parse the XML data into dynamic objects while preserving HTML tags, and use the MergeFieldEvent handler to retrieve HTML content and insert it in place of merge fields with proper formatting.
Steps to perform mail merge in Word with XML data containing HTML tags:
- Create a new .NET Core console application project.
- Install the Syncfusion.DocIO.Net.Core NuGet package as a reference to your project from NuGet.org.
Note:
Starting with v16.2.0.x, if you reference Syncfusion® assemblies from a trial setup or from the NuGet feed, include a license key in your projects. Refer to the link to learn about generating and registering a Syncfusion® license key in your application to use the components without a trial message.
- Include the following namespaces in the Program.cs file.
C#
using Syncfusion.DocIO.DLS;
using Syncfusion.DocIO;
- Use the following code example to perform mail merge in Word with XML data containing HTML tags.
C#
/ Dictionary to temporarily hold merge field HTML values and their positions.
Dictionary<WParagraph, Dictionary<int, string>> paraToInsertHTML = new Dictionary<WParagraph, Dictionary<int, string>>();
// Load the Word document template
using (WordDocument document = new WordDocument(Path.GetFullPath(@"Data/Template.docx")))
{
// Load the XML file that contains data to be merged
Stream xmlStream = System.IO.File.OpenRead(Path.GetFullPath(@"Data/Data.xml"));
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(xmlStream);
xmlStream.Dispose(); // Close and release the file stream
// Convert the XML data into a dynamic ExpandoObject structure
ExpandoObject allDataObject = new ExpandoObject();
GetDataAsExpandoObject(xmlDocument.LastChild, ref allDataObject);
// Traverse the dynamic data to extract and map mail merge records
if (allDataObject is IDictionary<string, object> allObjects &&
allObjects.ContainsKey("Root"))
{
var rootObjects = (allObjects["Root"] as List<ExpandoObject>)[0] as IDictionary<string, object>;
if (rootObjects.ContainsKey("Validator"))
{
var validatorObjects = (rootObjects["Validator"] as List<ExpandoObject>)[0] as IDictionary<string, object>;
// Iterate over each component inside Validator (e.g., Login, Dashboard)
foreach (var validatorObject in validatorObjects)
{
var componentMainTag = validatorObject.Key; // Typically "Component"
var componentData = validatorObject.Value as List<ExpandoObject>;
if (componentData != null)
{
// Create a mail merge data table for each component
MailMergeDataTable componentDataTable = new MailMergeDataTable(componentMainTag, componentData);
// Attach event handler to handle HTML merge fields
document.MailMerge.MergeField += new MergeFieldEventHandler(MergeFieldEvent);
// Execute group mail merge using nested data table
document.MailMerge.ExecuteGroup(componentDataTable);
}
}
}
}
// After mail merge is complete, insert HTML into placeholders
InsertHtml();
// Detach mail merge event handlers
document.MailMerge.MergeField -= new MergeFieldEventHandler(MergeFieldEvent);
// Save the updated document
document.Save(Path.GetFullPath(@"Output/Result.docx"), FormatType.Docx);
}
- Use the following code example to handle HTML content.
C#
void MergeFieldEvent(object sender, MergeFieldEventArgs args)
{
if (args.FieldName.Equals("Description"))
{
// Get the paragraph containing the current merge field
WParagraph paragraph = args.CurrentMergeField.OwnerParagraph;
// Get the index of the merge field inside the paragraph
int mergeFieldIndex = paragraph.ChildEntities.IndexOf(args.CurrentMergeField);
// Store the HTML field value with its position
Dictionary<int, string> fieldValues = new Dictionary<int, string>();
fieldValues.Add(mergeFieldIndex, args.FieldValue.ToString());
// Associate the paragraph with its corresponding HTML values
paraToInsertHTML.Add(paragraph, fieldValues);
// Remove the default text replacement; HTML will be inserted later
args.Text = string.Empty;
}
}
- Use the following code example to replace merge fields with actual HTML content using collected placeholders.
C#
void InsertHtml()
{
// Iterate each paragraph and its associated HTML values
foreach (KeyValuePair<WParagraph, Dictionary<int, string>> dictionaryItems in paraToInsertHTML)
{
WParagraph paragraph = dictionaryItems.Key;
Dictionary<int, string> values = dictionaryItems.Value;
foreach (KeyValuePair<int, string> valuePair in values)
{
int index = valuePair.Key;
string fieldValue = valuePair.Value;
// Insert HTML at the specified location in the paragraph
paragraph.OwnerTextBody.InsertXHTML(fieldValue, paragraph.OwnerTextBody.ChildEntities.IndexOf(paragraph), index);
}
}
// Clear dictionary after inserting all HTML
paraToInsertHTML.Clear();
}
- Use the following code example to recursively parse XML nodes into an ExpandoObject structure for easy access.
C#
void GetDataAsExpandoObject(XmlNode node, ref ExpandoObject dynamicObject)
{
try
{
// Check if node is simple text (possibly with HTML tags)
if (node.InnerText == node.InnerXml || (node.ChildNodes.Count == 1 && node.FirstChild.NodeType == XmlNodeType.Text))
{
if (!(dynamicObject as IDictionary<string, object>).ContainsKey(node.LocalName))
(dynamicObject as IDictionary<string, object>).Add(node.LocalName, node.InnerText);
}
else
{
List<ExpandoObject> childObjects;
// Reuse existing list if it already exists for this node
if ((dynamicObject as IDictionary<string, object>).ContainsKey(node.LocalName))
childObjects = (dynamicObject as IDictionary<string, object>)[node.LocalName] as List<ExpandoObject>;
else
{
childObjects = new List<ExpandoObject>();
(dynamicObject as IDictionary<string, object>).Add(node.LocalName, childObjects);
}
ExpandoObject childObject = new ExpandoObject();
// Recursively parse each child node
foreach (XmlNode childNode in node.ChildNodes)
{
GetDataAsExpandoObject(childNode, ref childObject);
}
childObjects.Add(childObject);
}
}
catch (Exception e)
{
Console.WriteLine("Error in XML reading: " + e.ToString());
}
}
You can download a complete working sample to perform mail merge in Word with XML data containing HTML tags from GitHub.
Take a moment to peruse the documentation where you can find basic Word document processing options along with features like mail merge, merge, split, and compare Word documents, find and replace text in the Word document, protect the Word documents, and most importantly, the PDF and Image conversions with code examples.
See Also
Conclusion
I hope you enjoyed learning about how to perform mail merge in Word with XML data containing HTML tags in a .NET Core Word document.
You can refer to our ASP.NET Core DocIO feature tour page to know about its other groundbreaking feature representations and documentation, and how to quickly get started with configuration specifications. You can also explore our ASP.NET Core DocIO example to understand how to create and manipulate data.
For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion®, you can try our 30-day free trial to check out our other controls.
If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!