Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Generate Word documents from Word templates using the Word 2007 XML object model

2.50/5 (6 votes)
16 Dec 2007CPOL 1   860  
How to generate Word documents from Word templates using the Word 2007 XML format.

Introduction

In many projects, developers need to generate reports in Word documents in a certain format or from a template. The old way of generating this using server-side Word instantiations will consume a lot of server resources and is not recommended. An alternative to this is Word generation using the Word 2007 XML object. Basic information about the Word 2007 XML format can be found here.

This article covers the generation of contract documents from a template on the server by populating the bookmarks and their styles.

Using the Code

This code requires Word 2007, and .NET Framework 3.0 or above to work. .NET 3.0 ships with a special DLL called WindowsBase.dll and a namespace called System.IO.Packaging, which are used to generate the Word documents without instantiating a Word object on the server.

C#
//Namespaces required
using System.IO;
using System.IO.Packaging;
using System.Xml;
using System.Collections.Generic;

//Variable and constants.
const string documentRelationshipType = 
  "http://schemas.openxmlformats.org/" + 
  "officeDocument/2006/relationships/officeDocument";
const string headerContentType = 
  "application/vnd.openxmlformats-" + 
  "officedocument.wordprocessingml.header+xml";
const string footerContentType = 
  "application/vnd.openxmlformats-" + 
  "officedocument.wordprocessingml.footer+xml";
XmlNamespaceManager nsManager;

//Method which will create the documents on the fly.

private void CreateWordDocument()
{
    Random RandomClass = new Random();
    int randomInt = RandomClass.Next();

    //Word template file
    string templateName = "Template.docx";

    //New file name to be generated from 
    string docFileName = "Doc_" + randomInt + ".docx";

    File.Copy(Server.MapPath(@"_Documents/" + templateName), 
              Server.MapPath(@"_Documents/" + docFileName),true);

    string fileName = Server.MapPath(@"_Documents/" + docFileName);

    PackagePart documentPart = null;
    Package package = 
      Package.Open(fileName, FileMode.Open, FileAccess.ReadWrite);

    //  Get the main document part (document.xml).
    foreach (System.IO.Packaging.PackageRelationship documentRelationship 
             in package.GetRelationshipsByType(documentRelationshipType))
    {
        NameTable nt = new NameTable();
        nsManager = new XmlNamespaceManager(nt);
        nsManager.AddNamespace("w", 
          "http://schemas.openxmlformats.org/wordprocessingml/2006/main");

        Uri documentUri = PackUriHelper.ResolvePartUri(
          new Uri("/", UriKind.Relative), documentRelationship.TargetUri);
        documentPart = package.GetPart(documentUri);

        #region Update Document Bookmarks
        //Get document xml
        XmlDocument xdoc = new XmlDocument();

        //xdoc.Load(documentPart.GetStream());
        xdoc.Load(documentPart.GetStream(FileMode.Open,FileAccess.Read));

        //Select all bookmark nodes
        XmlNodeList nodeList = 
          xdoc.SelectNodes("//w:bookmarkStart", nsManager);

        foreach (XmlNode node in nodeList)
        {
           // S_ADDRESS_V1 and S_ADDRESS_V2 are
           // the bookmarks defined in the template 
           if(this.SetBookmarkText(xdoc, node, "S_ADDRESS_V1", 
                  RandomClass.Next().ToString())) continue;

           if (this.SetBookmarkText(xdoc, node, "S_ADDRESS_V2", 
                  RandomClass.Next().ToString())) continue;
        }

        #endregion

        #region Update Header/Footer Bookmarks

        PackagePartCollection documentParts = package.GetParts();

        foreach (PackagePart part in documentParts)
        {
            //Update header bookmarks
            if (part.ContentType == headerContentType)
            {
                //Get document xml
                XmlDocument xheader = new XmlDocument();
                xheader.Load(part.GetStream(FileMode.Open, FileAccess.Read));

                //Select all bookmark nodes
                XmlNodeList headerNodeList = 
                  xheader.SelectNodes("//w:bookmarkStart", nsManager);
                foreach (XmlNode node in headerNodeList)
                {
                    //HEADER5 is the bookmark of header in template
                    if (this.SetBookmarkText(xheader, node, 
                          "HEADER5", "Test Header")) continue;
                }

                //Save 
                if (headerNodeList.Count > 0)
                {
                    StreamWriter streamHeader = 
                      new StreamWriter(part.GetStream(FileMode.Open, FileAccess.Write));
                    xheader.Save(streamHeader);
                    streamHeader.Close();
                }
            }

            //Update footer bookmarks
            if (part.ContentType == footerContentType)
            {
                //Get document xml
                XmlDocument xfooter = new XmlDocument();
                xfooter.Load(part.GetStream(FileMode.Open, FileAccess.Read));

 
                //Select all bookmark nodes
                XmlNodeList footerNodeList = 
                  xfooter.SelectNodes("//w:bookmarkStart", nsManager);

                foreach (XmlNode node in footerNodeList)
                {
                    //FOOTER_1_1
                    if (this.SetBookmarkText(xfooter, node, 
                          "FOOTER_1_1", "Number", true)) continue;
                    if (this.SetBookmarkText(xfooter, node, 
                          "FOOTER_1_2", "123456", true)) continue;
                }

                //Save 
                if (footerNodeList.Count > 0)
                {
                    StreamWriter streamFooter = 
                       new StreamWriter(part.GetStream(FileMode.Open, FileAccess.Write));
                    xfooter.Save(streamFooter);
                    streamFooter.Close();
                }
            }
        }

        #endregion

        StreamWriter streamPart = new StreamWriter(
           documentPart.GetStream(FileMode.Open, FileAccess.Write));
        xdoc.Save(streamPart);
        streamPart.Close();
    }

    package.Flush();
    package.Close();

    ////send response to browser
    /*string File_Name = "_Documents/" + docFileName;
    string popupScript = "<script language="'javascript'">" +
                     "window.open('" + File_Name + "', 'Document', " +
                     "'width=700, height=600, menubar=yes, resizable=yes')" +
                     "</script>";

    ClientScript.RegisterClientScriptBlock(this.GetType(), 
                  "PopupScriptOffer", popupScript);
     */
}

/// <summary>
/// 
/// </summary>
/// <param name="xdoc"></param>
/// <param name="node"></param>
/// <param name="bookmarkName"></param>
private bool SetBookmarkText(XmlDocument xdoc, XmlNode node, 
                             string bookmarkName, string bookmarkValue)
{
    if (node.NextSibling.Name.ToString() == "w:bookmarkEnd")
    {
        if (node.Attributes["w:name"].Value == bookmarkName)
        {
            //get the node previous sibling style
            //("w:rPr") to apply to the bookmark text
            XmlNode nodeStyle = node.PreviousSibling.CloneNode(true);

            //parent node "w:p"
            XmlNode bookmrkParent = node.ParentNode;

            XmlElement tagRun;
            tagRun = xdoc.CreateElement("w:r", 
                          nsManager.LookupNamespace("w"));
            bookmrkParent.AppendChild(tagRun);

            //if (nodeStyle != null && nodeStyle.FirstChild.Name == "w:rPr")
            //    tagRun.AppendChild(nodeStyle.FirstChild);

            if (nodeStyle.SelectSingleNode("//w:rPr", nsManager) != null)
                tagRun.AppendChild(nodeStyle.SelectSingleNode("//w:rPr", nsManager));

            XmlElement tagText;
            tagText = xdoc.CreateElement("w:t", 
                              nsManager.LookupNamespace("w"));
            tagRun.AppendChild(tagText);

            //*** insert text into part as a Text node 
            XmlNode nodeText;
            nodeText = xdoc.CreateNode(XmlNodeType.Text, 
                         "w:t", nsManager.LookupNamespace("w"));
            nodeText.Value = bookmarkValue;
            tagText.AppendChild(nodeText);

            return true;
        }
    }
    return false;
}

private bool SetBookmarkText(XmlDocument xdoc, XmlNode node, 
             string bookmarkName, string bookmarkValue, bool IsFooter)
{
    if (node.NextSibling.Name.ToString() == "w:bookmarkEnd")
    {
        if (node.Attributes["w:name"].Value == bookmarkName)
        {
            //get the node previous sibling style
            //("w:rPr") to apply to the bookmark text
            XmlNode nodeStyle = node.PreviousSibling.CloneNode(true);

            //parent node "w:p"
            XmlNode bookmrkParent = node.ParentNode;

            XmlElement tagRun;
            tagRun = xdoc.CreateElement("w:r", 
                           nsManager.LookupNamespace("w"));
            bookmrkParent.AppendChild(tagRun);

            if (nodeStyle.SelectSingleNode("//w:rPr", nsManager) != null)
            {
                XmlNode xfootStyle = 
                  nodeStyle.SelectSingleNode("//w:rPr", nsManager);

                //reduce font size for footer to 16.  <w:sz w:val="20" />
                /*if (IsFooter)
                {
                    xfootStyle.SelectSingleNode("//w:sz", 
                       nsManager).Attributes["w:val"].Value = "16";
                }*/
                tagRun.AppendChild(xfootStyle);
            }

            XmlElement tagText;
            tagText = xdoc.CreateElement("w:t", 
                            nsManager.LookupNamespace("w"));
            tagRun.AppendChild(tagText);

            //*** insert text into part as a Text node 
            XmlNode nodeText;
            nodeText = xdoc.CreateNode(XmlNodeType.Text, 
               "w:t", nsManager.LookupNamespace("w"));
            nodeText.Value = bookmarkValue;
            tagText.AppendChild(nodeText);

            return true;
        }
    }
    return false;
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)