Monday, November 3, 2014

Creating Word documents with Open XML SDK


Creating a simple Word document and adding content is relatively easy using the Open XML SDK (2.5). Here's a basic Hello World example:

public static void CreateWordDocument(string filename) {
    // Create a document by supplying the filename. 
    using (var wordDocument = WordprocessingDocument.Create(filename, WordprocessingDocumentType.Document)) {
        // Add the MainDocumentPart, root Document and the Body.
        var mainPart = wordDocument.AddMainDocumentPart();
        var document = mainPart.Document = new Document();
        var body = document.AppendChild(new Body());

        // Add a Paragraph and a Run with the specified Text
        var para = body.AppendChild(new Paragraph());
        var run = para.AppendChild(new Run());
        run.AppendChild(new Text("Hello World"));
    }
}

That's great for creating a simple document but what about when you want to add some real content and style it. Once you try and do that you quickly learn that what you are creating with the Open XML SDK truly is an empty document. This is not like opening Word and selecting "New Blank document" which has a bunch of preset styles available. To start having your document look like a real Word document (with things like styles and bullet lists) you have to start adding in classes like StyleDefinitionsPart and NumberingDefinitionsPart (and lots of additional stuff). Even when you add in those additional elements it's hard to make a document look as a good as Word out of the box.

An easier solution is to create your own template and use that as the basis for your new document. That way you will get a bunch of stuff already defined. The simplest way to do this is to open Word and create a new blank document and then save this as a Word template (*.dotx). You can also go into Word and customize the styles and add items like a header page and use that in your template. Once you have a template the code to create that basic Hello World example can be altered like so to use it:

public static void CreateFromTemplate(string templateFilename, string documentFilename) {
    // WordprocessingDocument.Create will overwrite an existing file. 
    // If we are using Open we have to delete the file first 
    // if we want to copy that behavior.
    if (File.Exists(documentFilename)) {
        File.Delete(documentFilename);
    }

    // Copy the template to the output file name.
    File.Copy(templateFilename, documentFilename);

    // Now open the copied file
    using (var wordDocument = WordprocessingDocument.Open(documentFilename, true)) {
        // We need to change the file type from template to document.
        wordDocument.ChangeDocumentType(WordprocessingDocumentType.Document);

        // MainDocumentPart, root Document and Body already exist just access them
        var mainPart = wordDocument.MainDocumentPart;
        var document = mainPart.Document;
        var body = document.Body;

        // Add a Paragraph and a Run with the specified Text
        var para = body.AppendChild(new Paragraph());
        var run = para.AppendChild(new Run());
        run.AppendChild(new Text("Hello World"));

        document.Save();
    }
}

It's a little more verbose but now you have a document with lots of predefined style ready to add content.