Skip to content

Convert .dotx to .docx

Olivier Nizet edited this page Jun 13, 2017 · 1 revision

Here is a quick tip to convert a template to a document (dotx -> docx). Renaming the extension of the filename is not the solution ;-)

using (WordprocessingDocument template = WordprocessingDocument.Open(documentStream, true))
{
    template.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);

    MainDocumentPart mainPart = template.MainDocumentPart;
    mainPart.DocumentSettingsPart.AddExternalRelationship(
           "http://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate",
           new Uri(@"C:\temp.dotx", UriKind.Absolute));

    ...
}

The short lines of code above do the tricks. I found that the attachedTemplate link should be added, when using a WinMerge to see the difference between a dotx and a docx saved by Word. There is a lot of garbage but only that link is mandatory. You can put whatever you want in the Uri of the attached template, it's purely informative and may not exists. In theory, it should refer to the location of the template used to build the document.

Note: ChangeDocumentType requires a writable WordProcessingDocument. In the complete source code, I don’t want to overwrite my template so I copy the initial template to a writable temporary stream.

Complete source code

using System;
using System.IO;
using DocumentFormat.OpenXml.Packaging;

namespace TemplateConverter
{
    class Program
    {
        static void Main(string[]() args)
        {
            MemoryStream documentStream;
            String templatePath = Path.Combine(Environment.CurrentDirectory, "template.dotx");
            using (Stream tplStream = File.OpenRead(templatePath))
            {
                documentStream = new MemoryStream((int)tplStream.Length);
                CopyStream(tplStream, documentStream);
                documentStream.Position = 0L;
            }

            using (WordprocessingDocument template = WordprocessingDocument.Open(documentStream, true))
            {
                // We convert our template to a docx. These 2 lines of code do the tricks. The attached template
                // link refer to the location of the template used to build the document. I just hard-code a
                // dummy link (it's useless)
                template.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);

                MainDocumentPart mainPart = template.MainDocumentPart;
                mainPart.DocumentSettingsPart.AddExternalRelationship(
                    "http://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate",
                    new Uri(templatePath, UriKind.Absolute));

                mainPart.Document.Save();
            }

            string path = "test.doc";
            File.WriteAllBytes(path, documentStream.ToArray());

            // Run Word to open the document:
            System.Diagnostics.Process.Start(path);
        }

        /// <summary>
        /// Write the content of a stream into another.
        /// </summary>
        public static void CopyStream(Stream source, Stream target)
        {
            if (source != null)
            {
                MemoryStream mstream = source as MemoryStream;
                if (mstream != null) mstream.WriteTo(target);
                else
                {
                    byte[]() buffer = new byte[2048](2048);
                    int length = buffer.Length, size;

                    while ((size = source.Read(buffer, 0, length)) != 0)
                        target.Write(buffer, 0, size);
                }
            }
        }
    }
}