Wiki

Clone wiki

Aspose for OpenXML / Dealing with MailMerge using OpenXML SDK

Dealing with MailMerge

Steps to perform a mail merge

First, you use Microsoft Word to create and design a Word document normally called a template. Note that the document does not have to be a Microsoft Word Template (.dot), it can be a normal .doc document. You insert some special fields called merge fields into the template in places where you want data from your data source to be later inserted.

Below is the code for inserting data in mail merge fields:

using OpenXML SDK

#!c#

//Will not deal with mergefields nested in other fields (IF, for example)
    private void btnGetMergeFields_Click(object sender, EventArgs e)
    {
        string fileName = @"C:\test\MergeFields.docx";
        using (WordprocessingDocument pkgDoc = WordprocessingDocument.Open(fileName, true))
        {
            string fieldList = string.Empty;
            Document doc = pkgDoc.MainDocumentPart.Document;
            //Get all field code elements in the document
            IEnumerable<FieldChar> fldChars = doc.Descendants<FieldChar>();
            if (fldChars == null) return; //No field codes in the document

            // bool fldStart = false;
            FieldChar fldCharStart = null;
            FieldChar fldCharEnd = null;
            FieldChar fldCharSep = null;
            FieldCode fldCode = null;
            string fldContent = String.Empty;
            foreach (FieldChar fldChar in fldChars)
            {
                string fldCharPart = fldChar.FieldCharType.ToString();
                switch (fldCharPart)
                {
                    case "begin": //start of the field
                        fldCharStart = fldChar;
                        //get the field code, which will be an instrText element
                        // either as sibling or as a child of the parent sibling
                        fldCode = fldCharStart.Parent.Descendants<FieldCode>().FirstOrDefault();
                        if (fldCode == null) //complex field
                        {
                            fldCode = fldCharStart.Parent.NextSibling<Run>().Descendants<FieldCode>().FirstOrDefault();
                        }
                        if (fldCode != null && fldCode.InnerText.Contains("MERGEFIELD"))
                        {
                            fldContent = fldCode.InnerText;
                            fieldList += fldContent + "\n";
                        }
                        break;
                    case "end": // end of the field
                        fldCharEnd = fldChar;
                        break;
                    case "separate": //complex field with text result
                        //we want to put the database content in this text run
                        //yet still remove the field code
                        //If there's no "separate" field char for the current field,
                        //we need to insert it somewhere else
                        fldCharSep = fldChar;
                        break;
                    default:
                        break;
                }
                if ((fldCharStart != null) && (fldCharEnd != null)) //start and end field codes have been found
                {
                    if (fldCharSep != null)
                    {
                        DocumentFormat.OpenXml.Wordprocessing.Text elemText = (DocumentFormat.OpenXml.Wordprocessing.Text)fldCharSep.Parent.NextSibling().Descendants<DocumentFormat.OpenXml.Wordprocessing.Text>().FirstOrDefault();
                        elemText.Text = fldContent;
                        //Delete all the field chars with their runs
                        DeleteFieldChar(fldCharStart);
                        DeleteFieldChar(fldCharEnd);
                        DeleteFieldChar(fldCharSep);
                        fldCode.Remove();
                    }
                    else
                    {
                        DocumentFormat.OpenXml.Wordprocessing.Text elemText = new DocumentFormat.OpenXml.Wordprocessing.Text(fldContent);
                        fldCode.Parent.Append(elemText);
                        fldCode.Remove();
                        //Delete all the field chars with their runs
                        DeleteFieldChar(fldCharStart);
                        DeleteFieldChar(fldCharEnd);
                        DeleteFieldChar(fldCharSep);
                    }
                    fldCharStart = null;
                    fldCharEnd = null;
                    fldCharSep = null;
                    fldCode = null;
                    fldContent = string.Empty;
                }

            }
            this.txtMessages.Text = fieldList;
        }
    }
    private void DeleteFieldChar(OpenXmlElement fldCharStart)
    {
        Run fldRun = (Run) fldCharStart.Parent;
        fldRun.RemoveAllChildren();
        fldRun.Remove();
    }
    }

using Aspose SDK

#!c#

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Aspose.Words;

namespace MailMerge
{
    class Program
    {
        static void Main(string[] args)
        {
            string projectFiles = Path.GetFullPath("../../Files/");

            Document doc = new Document(projectFiles + "Template.docx");

            // Fill the fields in the document with user data.
            doc.MailMerge.Execute(
                new string[] { "FullName", "Company", "Address", "Address2", "City" },
                new object[] { "James Bond", "MI5 Headquarters", "Milbank", "", "London" });

            // Saves the document to disk.
            doc.Save(projectFiles + "MailMerge Result Out.docx");

            System.Console.WriteLine("Press any key to continue.");
            System.Console.ReadKey();
        }
    }
}
Source: https://bitbucket.org/asposemarketplace/aspose-for-openxml/src/ffec3cde9d87478f6831c79526ff5dcfadf529c0/Aspose.Words/MailMerge/?at=master

Updated