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






2.50/5 (6 votes)
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.
//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;
}