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.
using System.IO;
using System.IO.Packaging;
using System.Xml;
using System.Collections.Generic;
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;
private void CreateWordDocument()
{
Random RandomClass = new Random();
int randomInt = RandomClass.Next();
string templateName = "Template.docx";
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);
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
XmlDocument xdoc = new XmlDocument();
xdoc.Load(documentPart.GetStream(FileMode.Open,FileAccess.Read));
XmlNodeList nodeList =
xdoc.SelectNodes("//w:bookmarkStart", nsManager);
foreach (XmlNode node in nodeList)
{
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)
{
if (part.ContentType == headerContentType)
{
XmlDocument xheader = new XmlDocument();
xheader.Load(part.GetStream(FileMode.Open, FileAccess.Read));
XmlNodeList headerNodeList =
xheader.SelectNodes("//w:bookmarkStart", nsManager);
foreach (XmlNode node in headerNodeList)
{
if (this.SetBookmarkText(xheader, node,
"HEADER5", "Test Header")) continue;
}
if (headerNodeList.Count > 0)
{
StreamWriter streamHeader =
new StreamWriter(part.GetStream(FileMode.Open, FileAccess.Write));
xheader.Save(streamHeader);
streamHeader.Close();
}
}
if (part.ContentType == footerContentType)
{
XmlDocument xfooter = new XmlDocument();
xfooter.Load(part.GetStream(FileMode.Open, FileAccess.Read));
XmlNodeList footerNodeList =
xfooter.SelectNodes("//w:bookmarkStart", nsManager);
foreach (XmlNode node in footerNodeList)
{
if (this.SetBookmarkText(xfooter, node,
"FOOTER_1_1", "Number", true)) continue;
if (this.SetBookmarkText(xfooter, node,
"FOOTER_1_2", "123456", true)) continue;
}
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();
}
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)
{
XmlNode nodeStyle = node.PreviousSibling.CloneNode(true);
XmlNode bookmrkParent = node.ParentNode;
XmlElement tagRun;
tagRun = xdoc.CreateElement("w:r",
nsManager.LookupNamespace("w"));
bookmrkParent.AppendChild(tagRun);
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);
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)
{
XmlNode nodeStyle = node.PreviousSibling.CloneNode(true);
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);
tagRun.AppendChild(xfootStyle);
}
XmlElement tagText;
tagText = xdoc.CreateElement("w:t",
nsManager.LookupNamespace("w"));
tagRun.AppendChild(tagText);
XmlNode nodeText;
nodeText = xdoc.CreateNode(XmlNodeType.Text,
"w:t", nsManager.LookupNamespace("w"));
nodeText.Value = bookmarkValue;
tagText.AppendChild(nodeText);
return true;
}
}
return false;
}