Geeks With Blogs
Dan Bedassa
This is a step by step instruction on how to dynamically generate MS Word 2007 documents.

Background on Word 2007 Document Internals

Word 2007 document is based on the Office Open XML file formats. As you will see, the Office Open XML file formats are based on standard ZIP file technology. Each top-level file is saved as a ZIP archive, which means you will be able to open a Word document just as you would any other ZIP file and look inside.
Note that the 2007 Microsoft Office system applications such as Word and Excel have introduced file extensions for documents that use the new format. For example, the .docx extension is used for Word documents stored in the Office Open XML file formats while the more familiar .doc extension continues to be used for Word docs stored in the binary format.

Let’s create a new document in Word 2007 and add "Hello Word" as the text. Save the document using the default format to a new file named Hello.docx and close Word. Next, locate Hello.docx using Windows Explorer and rename it Hello.zip. Open Hello.zip and see the structure of folders and files that Word has created inside (see Figure).



Figure 1 DOCX File is a ZIP Archive

The top-level file (Hello.docx) is known as a package. Since a package is implemented as a standard ZIP archive, it automatically provides compression and it makes its contents instantly accessible to many existing utilities and APIs on both Windows platforms and other platforms alike.

Inside a package there are two kinds of internal components: parts and items. In general, parts contain content and items contain metadata describing the parts.

A basic package contains an XML file called [Content_Types].xml at the root, along with three directories: _rels, docProps, and a directory specific for the document type (for example, in a .docx word processing package, there would be a word directory). The word directory contains the document.xml file which is the core content of the document.

A part is named using a Uniform Resource Identifier (URI) that contains its relative path within the package file combined with the part file name. For example, the main part within the package for a Word document is /word/document.xml. Here are a few more typical part names you will find inside the package for a simple Word document:
  • /[Content_Types].xml
    This file describes the contents of the package. It also contains a mapping for file extensions and overrides for specific URIs.
  • _rels
    This directory contains relationships for the files within the package. To find the relationships for a specific file, look for the _rels directory that is a sibling of the file, and then for a file that has the original file name with a .rels appended to it. For example, if the content types file had any relationships, there would be a file called [Content_Types].xml.rels inside the _rels directory.
  • /_rels/.rels
    This file is where the package relationships are located. Applications look here first. Viewing in a text editor, one will see it outlines each relationship for that section. In a minimal document containing only the basic document.xml file, the relationships detailed are metadata and document.xml.
  • /docProps/core.xml
    This file contains the core properties for any Office Open XML document.
  • /word/document.xml
    This file is the main part for any Word document – which we will be manipulating in our code.

The Project

We will be using Visual Studio 2008, .NET Framework 3.5, the NorthWind database and a simple Word template in our application.
Step 1 – Create a Word 2007 template.
Create a simple Word 2007 file with placeholders enclosed between two #’s (like #ORDERID#) and save it as ‘MyTemplate.docx’
Below is the content I used:

From: My Company
#ADDRESS#
#CITY#, #REGION#, #POSTCODE#
#COUNTRY#
Dear #CUSTOMERID#
We're pleased to inform you that your order number #ORDERID# is going to be shipped on #SHIPPEDDATE#.
If you have any questions or comments, please feel free to give us a call at #HOMEPHONE#
Regards,
#FIRSRNAME# #LASTNAME#
#TITLE#



For More information

http://openxmldeveloper.org/
http://www.codeproject.com/KB/cs/GenerateWord2007.aspx
http://en.wikipedia.org/wiki/Office_Open_XML
http://msdn.microsoft.com/en-us/magazine/cc163526.aspx#S1


We will replace the place holders with values from the Orders table of the Northwind database.
Step 2 – Create an OrderInformation class
This class simply represents an Order object with properties for OrderID, CustomerID,….
Step 3 – Create a GenerateDocument class
A main method, public void GenerateWord( OrderInformation orderInfo), is implemented to generate the new document named after the value of OrderID of the current Order.
In this class, System.IO.Package is used to replicate the template, replacing the place holder variables in the /word/document.xml file with the actual values from the current Order.
Below is the code:
public void GenerateWord( OrderInformation orderInfo)
{
string templateDoc = string.Format("{0}{1}", ConfigurationManager.AppSettings["TemplateFolder"], ConfigurationManager.AppSettings["TemplateFile"]);
string filename = string.Format("{0}{1}.docx", ConfigurationManager.AppSettings["OutputFolder"], orderInfo.OrderID);

// Copy a new file name from template file
File.Copy(templateDoc, filename, true);

// Open the new Package
Package pkg = Package.Open(filename, FileMode.Open, FileAccess.ReadWrite);

// Specify the URI of the part to be read
Uri uri = new Uri("/word/document.xml", UriKind.Relative);
PackagePart part = pkg.GetPart(uri);

XmlDocument xmlMainXMLDoc = new XmlDocument();
xmlMainXMLDoc.Load(part.GetStream(FileMode.Open,FileAccess.Read));

xmlMainXMLDoc.InnerXml = ReplacePlaceHoldersInTemplate(orderInfo, xmlMainXMLDoc.InnerXml);

// Open the stream to write document
StreamWriter partWrt = new StreamWriter(part.GetStream(FileMode.Open, FileAccess.Write));
//doc.Save(partWrt);
xmlMainXMLDoc.Save(partWrt);

partWrt.Flush();
partWrt.Close();
pkg.Close();
}
private string ReplacePlaceHoldersInTemplate(OrderInformation orderInfo, string templateBody)
{
//#ADDRESS#
templateBody = templateBody.Replace("#ADDRESS#", orderInfo.FirstName);

//#CITY#
templateBody = templateBody.Replace("#CITY#", orderInfo.City);

}
Step 4 – Implement a web or WinForms application utilizing the above classes
Here is a sample button_Click handler:
protected void btnFrom_Click(object sender, EventArgs e)
{
string orderID = “1234”;// lstOrders.SelectedValue;

//generate documet
OrderInformation orderInfo;
GenerateDocument doc = new GenerateDocument();
orderInfo = doc.GetOrderInformation(orderID);
doc.GenerateWord(orderInfo);

}
Posted on Friday, January 16, 2009 1:02 PM | Back to top


Comments on this post: Dynamically generating Word 2007 (.docx) documents using .net

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
You should elaborate a bit more on the code; eg. the copy-past below from http://www.codeproject.com/KB/office/GenerateWord2007.aspx

///Get Data From SQL Server
public OrderInformation GetOrderInformation()
{
string sqlQuery;
sqlQuery = "SELECT o.OrderID, o.CustomerID, o.ShippedDate, ";
sqlQuery = sqlQuery + "e.LastName, e.FirstName, e.Title,e.Address, _
e.City, e.Region, e.PostalCode,e.HomePhone,e.Country ";
sqlQuery = sqlQuery + "FROM Orders o ";
sqlQuery = sqlQuery + "INNER JOIN Employees e ON _
e.EmployeeID = o.EmployeeID ";
sqlQuery = sqlQuery + "WHERE o.OrderID = 10250";
using (SqlConnection conn = new SqlConnection_
(@"Integrated Security=SSPI;Persist Security Info=False;_
Initial Catalog=Northwind;Data Source=localhost"))
{
SqlCommand cmd = new SqlCommand(sqlQuery, conn);
cmd.Connection.Open();

SqlDataReader sdr = cmd.ExecuteReader();
sdr.Read();
OrderInformation orderInfo = new OrderInformation();
orderInfo.OrderID = sdr.GetInt32(0);
orderInfo.CustomerID = sdr.GetString(1);
orderInfo.ShippedDate = sdr.GetDateTime(2);
orderInfo.LastName = sdr.GetString(3);
orderInfo.FirstName = sdr.GetString(4);
orderInfo.Title = sdr.GetString(5);
orderInfo.Address = sdr.GetString(6);
orderInfo.City = sdr.GetString(7);
orderInfo.Region = sdr.GetString(8);
orderInfo.PostCode = sdr.GetString(9);
orderInfo.HomePhone = sdr.GetString(10);
orderInfo.Country = sdr.GetString(11);

return orderInfo;
}
}
Left by Jakob Flygare on Jun 24, 2009 10:12 AM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
You need to expand this a lot more before it becomes even remotely useful - step 2 for instance, why even bother writing it if that's all you had to say? Not helpful.
Left by Jane on Oct 18, 2009 5:04 PM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
I like this, its simple and effective. You dont need to elaborate on step 2 as the point of the article is to dynamically generate a doc and update using openXML.

VB.net version below.

Dim pkg As Package = Package.Open("C:\Test\abc.docx", FileMode.Open, FileAccess.ReadWrite)

' Specify the URI of the part to be read
Dim Uri As Uri = New Uri("/word/document.xml", UriKind.Relative)
Dim part As PackagePart = pkg.GetPart(Uri)

Dim xmlMainXMLDoc As XmlDocument = New XmlDocument()
xmlMainXMLDoc.Load(part.GetStream(FileMode.Open, FileAccess.Read))

xmlMainXMLDoc.InnerXml = ReplacePlaceHoldersInTemplate(xmlMainXMLDoc.InnerXml)

' Open the stream to write document
Dim partWrt As StreamWriter = New StreamWriter(part.GetStream(FileMode.Open, FileAccess.Write))
'doc.Save(partWrt);
xmlMainXMLDoc.Save(partWrt)

partWrt.Flush()
partWrt.Close()
pkg.Close()

' This can be update to get values from anywhere. In this example it simply uses the harcoded string,. 'test'.

Private Function ReplacePlaceHoldersInTemplate(ByVal templateBody As String) As String

'#ADDRESS#
templateBody = templateBody.Replace("#ADDRESS#", "test")

'#CITY#
templateBody = templateBody.Replace("#CITY#", "test")

Return templateBody

End Function
Left by will on Dec 02, 2009 6:10 AM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
Dan,
Nice intro, what I need to know now is what happens when you get a field that isn't populated, ie empty. How do you get to remove the tag and also the line so there are no messy spaces in the resulting document. I have tried replacing with empty string, but that still leaves the space.

Feedback on this appreciated.
regards
G.
Left by Geoff Hirst on Jun 29, 2010 4:53 AM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
Can you please tell me how to use this if I want to read values from an xml file instead of a database? It would be greatly appreciated. Thanks!
Left by Gemys62 on Sep 06, 2010 3:48 PM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
Gemys62, It doesn't matter where you where you read the values from (database, XML file, flat file, ...) just construct the OrderInformation object and pass it to the GenerateWord( OrderInformation orderInfo) method.
Left by Dan on Sep 08, 2010 11:02 PM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
Hi all

i am reading a MS word document using the code below

using (WordprocessingDocument wdDoc = WordprocessingDocument.Open(TemplatePath, true))
{
string docText;

using (var sr = new StreamReader(wdDoc.MainDocumentPart.GetStream()))
{
docText = sr.ReadToEnd();
}

in this document i have specified some variables starting with "$" and then replacing these variables with some custom data

docText = docText.Replace("$Name", name);

but my docText stream whcih infact contains an XML string, represents "$" and "Name" in 2 different tags, thus my code doesn't find "$Name" and my code does not work.


Can anyone suggest any solution/idea or any approach to overcome this problem.
Left by Shafaqat Ali on Jan 17, 2011 11:44 AM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
Great tutorial!

Is there a way to inert a new line to the field?

If for example I want to dynamically add several paragraphs?
Left by Zare on Feb 09, 2011 10:27 AM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
Can we do the same to dynamically generate .xlsx files with a template
Left by Sachidananda on Jun 15, 2011 10:27 AM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
Is it work in vertion 2.0? if so can you please share any source code for thar
Left by praveen on Jul 04, 2011 11:04 AM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
can I have the full code?
I am getting issue with this one
Left by pasindu on Jul 06, 2011 1:50 AM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
I've tried to replicate the method, you described here, but it does not work for me =( I've got an error, when open a generated docx =(
Left by anton on Sep 30, 2011 8:50 AM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
My mistake! It works fine)

How can I add a table to the template? Is it possible?
Left by anton on Sep 30, 2011 8:55 AM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
Hi
There is any way to bind a data table fields directly to content controls.
Left by Vahid on Jan 09, 2012 6:37 AM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
That's the exact question I have,

Is there any way to bind data from the database to the file directly?
Left by Hetal Patel on Jan 24, 2012 4:23 PM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
Maybe some of you may find interesting PHPDocX (http://www.phpdocx.com). Although is not based in .nt but PHP it is a pretty flexible library with lots of functionalities thta you may find useful.
Left by Eduardo on May 15, 2012 2:31 AM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
Cheers man, finally a simple and WORKING example, easy to understand and work with!
Left by orshee on Sep 07, 2012 10:59 AM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
Take a look at Docentric Toolkit (http://www.docentric.com/), a commercial tool for mail merge, document generation and MS Word reporting in .NET based on the similar concepts which offers:
- Superior mail-merge features such as: data bound images, charts, (arbitrary level of) nested tables/bulleted list, subdocuments, horizontal tables, headers & footers etc.
- Very original approach for designing templates called "visual mail-merge": with the help of special MS Word Add-In and point-and-click technique you can bind template data tags against any property path in a .NET object graph which is data source of the template. This way designing of templates becomes very efficient since you always have a transparent list of broken binding paths. In short - it provides ultimately the best user experience for template design on the market today!
- Document Generation is OpenXML based, stable and fast and can be implemented in only a few lines of code.
- Can be used as alternative to reporting tools where it is desired to enable end-users to design/maintain templates.
- Can be used in cloud based solutions.
Left by Sandra on Jul 26, 2013 6:33 AM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
This is a .NET Library for Word that i think can solve almost every problem that has been mentioned above. It uses C#/.NET/VB.NET to create, read, modify and even convert word files to many other file formats. I hope it will solve your problem.
Left by Sfetlana on Oct 08, 2013 5:09 AM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
I just want to point to a very good fully featured template-based document generation solution for those that have to deal with a lot of complex templates:
http://www.docentric.com

This toolkit also supports tagging inside headers and footers, images, charts.
Left by LukeP on Mar 23, 2014 3:35 PM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
Check out Nevron Text Editor for WPF, WinForms and Silverlight (http://www.nevron.com)
Left by Bob Milanov on Apr 24, 2014 8:38 AM

# re: Dynamically generating Word 2007 (.docx) documents using .net
Requesting Gravatar...
can we use this technology in php
Left by aryan on Jun 11, 2014 3:19 AM

Your comment:
 (will show your gravatar)


Copyright © DanBedassa | Powered by: GeeksWithBlogs.net | Join free