How to create a document from a template (dotx, dotm) and attach to it using Open XML SDK

One of the needs to use Open XML SDK is to create documents on server side. In case of Open XML, it is recommended to create a document from another one rather than creating a document from scratch. After creating a copy of a document, you can modify its content. Sample code is given below:

System.IO.File.Copy(sourceFile, destinationFile);
using (WordProcessingDocument document = WordProcessingDocument.Open(destinationFile, true))
{
   // Code to modify the document
}

However, we need to follow a different approach when it comes to creating a document from an existing template (.dotx) file. Consider the scenario where a user wants to maintain the connection to the template in the newly created document (which is similar to when we create a document from a template manually). In this scenario, we need to implement additional steps.

The following steps list how to create a document from a template using Open XML SDK and attach it to the document.   

  1. Create a copy of the template and open it for editing
  2. Change the document type to WordProcessingDocumentType.Document
  3. Create an AttachedTemplate object
  4. Append the AttachedTemplateobject to the DocumentSettingsPart.Settings.
  5. Add an External Relationship of type AttachedTemplate to the DocumentSettingsPart.Settings.
  6. Save the document.

The first step is to create a copy of the template and open it for editing. We can use System.IO.File.Copy() method to create a copy. Once the copy is created, use WordProcessingDocument.Open() method to open the file for editing. Consider that we have a template with the name Sample.dotx on the current directory from which we need to create the document.

string sourceFile = Path.Combine(Environment.CurrentDirectory, “Sample.dotx”);
string destinationFile = Path.Combine(Environment.CurrentDirectory, “SampleDocument.docx”);
using(WordProcessingDocument document = WordProcessingDocument.Open(destinationFile, true))
{
// Rest of the code
}

Even though the extension of the destinationFile is “docx”, it is still a template. We need to change the document type using ChangeDocumentType() method  

document.ChangeDocumentType(WordProcessingDocumentType.Document);

The next step is to create an AttachedTemplate object and assign a relationship id to it. Assigning the relationship id is important because, the document will identify the attached template using this id.

AttachedTemplate attachedTemplate1 = new AttachedTemplate() { Id = “relationId1”};

Now we can append the AttachedTemplate to the DocumentSettingsPart as given below:

MainDocumentPart mainPart = document.MainDocumentPart;
DocumentSettingsPart documentSettingsPart1 = mainPart.DocumentSettingsPart;
documentSettingsPart1.Settings.Append(attachedTemplate1);

An essential step is to add an external relationship of type AttachedTemplate and specify the URI of the document template from which the document is created. An important point to be remembered is to add the relationship id that we previously specified forAttachedTemplate object.

documentSettingsPart1.AddExternalRelationship("https://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate", new Uri(sourceFile, UriKind.Absolute), "relationId1");

Now you can add other code to modify the document and then save it.

Follow the steps given below to create a document from a template using Open XML SDK in Visual Studio 2010.

  1. Download and install Open XML SDK 2.0 from the following location:

    https://www.microsoft.com/download/en/details.aspx?displaylang=en&id=5124

  2. Open Visual Studio 2010 and create a new Console application in C#

  3. Add a reference to DocumentFormat.OpenXml and WindowsBase assemblies.

  4. Create a document in the current directory with the name “Sample.dotx”

  5. Replace the code with the one given below and run it:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml.Packaging;
using System.IO;

namespaceGenerateDocumentFromTemplate
{
    class Program
    {
        static void Main(string[] args)
        {
            string destinationFile = Path.Combine(Environment.CurrentDirectory, "SampleDocument.docx");
            string sourceFile = Path.Combine(Environment.CurrentDirectory, "Sample.dotx");
            try
            {
                // Create a copy of the template file and open the copy
                File.Copy(sourceFile, destinationFile, true);
                using (WordprocessingDocument document = WordprocessingDocument.Open(destinationFile, true))
                {
                    // Change the document type to Document
                    document.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);

                    // Get the MainPart of the document
                    MainDocumentPart mainPart = document.MainDocumentPart;

                    // Get the Document Settings Part
                    DocumentSettingsPart documentSettingPart1 = mainPart.DocumentSettingsPart;

                    // Create a new attachedTemplate and specify a relationship ID
                    AttachedTemplate attachedTemplate1 = new AttachedTemplate() { Id = "relationId1" };

                    // Append the attached template to the DocumentSettingsPart
                    documentSettingPart1.Settings.Append(attachedTemplate1);

                    // Add an ExternalRelationShip of type AttachedTemplate.
                    // Specify the path of template and the relationship ID
                    documentSettingPart1.AddExternalRelationship("https://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate", new Uri(sourceFile, UriKind.Absolute), "relationId1");

                    // Save the document
                    mainPart.Document.Save();
 
                   Console.WriteLine("Document generated at " + destinationFile);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            { 
                Console.WriteLine("\nPress Enter to continue…");
                Console.ReadLine();
            }
        }
    }
}