Click here to Skip to main content
15,860,859 members
Articles / Web Development / ASP.NET

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

Rate me:
Please Sign up or sign in to vote.
2.50/5 (6 votes)
16 Dec 2007CPOL 44.9K   858   27   10
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)


Written By
Web Developer TCS Hyderabad
India India
I am a Software Engineer working for TCS.

I have an experience in ASP, ASP.NET, C#, SQL Server 2005.

Comments and Discussions

 
QuestionImport data to DOCX template Pin
Johnny Glenn26-Mar-12 22:52
Johnny Glenn26-Mar-12 22:52 
AnswerRe: Import data to DOCX template Pin
hugoro6-Jun-14 14:43
hugoro6-Jun-14 14:43 
GeneralMy vote of 3 Pin
GoodPanos27-May-11 9:58
professionalGoodPanos27-May-11 9:58 
Generalinserting tab's Pin
ek45271-May-09 5:56
ek45271-May-09 5:56 
GeneralCode changes Pin
Paulo Vaz28-Jan-09 15:33
Paulo Vaz28-Jan-09 15:33 
QuestionPrinting Pin
Sevententh28-Oct-08 22:00
Sevententh28-Oct-08 22:00 
AnswerRe: Printing Pin
Praveen Bonakurthi22-Nov-08 10:12
Praveen Bonakurthi22-Nov-08 10:12 
Questionbookmark question Pin
richardcruz29-May-08 1:57
richardcruz29-May-08 1:57 
GeneralGenerate the word documents from word templates using word 2007 XML object model Pin
Member 402700828-Apr-08 11:35
Member 402700828-Apr-08 11:35 
GeneralRe: Generate the word documents from word templates using word 2007 XML object model Pin
lepipele28-Jan-09 17:32
lepipele28-Jan-09 17:32 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.