When working with Microsoft Word automation there is often the requirement to create documents from define templates. With the addition of the OpenXml specification it is now possible to do this safely within server side code.

In a recent project I came across this requirement where a new Word document needed to be created based upon a template, with the addition of adding a custom XML part into the document. The custom XML part was used to perform bindings to a content controls within the document. Using OpenXml this became an easy task, as I will show.

The main processing I performed to achieve the Word Document creation was opening the required template document as a stream, and then creating a new document, as a MemoryStream, based on this based on this template:

using (MemoryStream documentStream = new MemoryStream((int)this.templateStream.Length))
{
templateStream.Position = 0L;
byte[] buffer = new byte[2048];
int length = buffer.Length;
int size;
while ((size = templateStream.Read(buffer, 0, length)) != 0)
{
documentStream.Write(buffer, 0, size);
}
documentStream.Position = 0L;

// Modify the document to ensure it is correctly marked as a Document and not Template
using (WordprocessingDocument document = WordprocessingDocument.Open(documentStream, true))
{
document.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
}

// Add the XML into the document and save to the correct location.
ProcessDocumentXml(inputDocument, documentStream);
File.WriteAllBytes(documentPath, documentStream.ToArray());
}

The ChangeDocumentType operation is critical to this process. This operation, provided by the OpenXml SDK, ensures the document is no longer marked as a Template but rather as a Document.

In this example I save stream as a file to a defined document path. One could just as easily write the response to say a web response stream.

To define Word documents from templates this is all the code one needs to write. However as you can see there is an additional step defined in this process called ProcessDocumentXml. It is this operation that performs the addition requirement to insert a custom Xml document into the Word Document.

private static void ProcessDocumentXml(XDocument inputDocument, Stream documentStream)
{
// Open the document in the stream and replace the custom XML part
using (Package packageFile = Package.Open(documentStream, FileMode.Open, FileAccess.ReadWrite))
{
PackagePart packagePart = null;

// Find part containing the correct namespace
foreach (PackagePart part in packageFile.GetParts())
{
if (part.ContentType.Equals("application/xml", StringComparison.OrdinalIgnoreCase))
{
using (XmlReader reader = XmlReader.Create(part.GetStream()))
{
if (reader != null)
{
reader.MoveToContent();
if (reader.NamespaceURI == "MyCustomXmlNamespace")
{
packagePart = part;
break;
}
}
}
}
}

if (packagePart != null)
{
// Delete the existing XML part
Uri uriData = packagePart.Uri;
if (packageFile.PartExists(uriData))
{
packageFile.DeletePart(uriData);
}

// Load the custom XML data
PackagePart pkgprtData = packageFile.CreatePart(uriData, CdsaHelper.DataContentType);
using (XmlWriter writer = XmlWriter.Create(pkgprtData.GetStream()))
{
inputDocument.Save(writer);
}
}
}
}

To replace a custom XML part within a Word Document one merely has to locate the necessary document part, usually by document namespace, and then perform the necessary Delete and Create operations; effectively an Update.

Hopefully this demonstrates the ease with which one can create Word Document from templates, using server side code. The ability to also insert custom Xml parts into the document provides he additional ability to customise the content of a document, once again within server side code.

Written by Carl Nolan