Taking Advantage of Bound Content Controls
Happy New Year! I hope everyone had a good holiday. For my first post of the New Year I want to talk about content controls and how this technology provides true data/view separation in Wordprocessing documents. In my previous post, I showed you how to use content controls to provide semantic structure within documents. Today, I am going to show you how to go one step further by leveraging the ability of content controls to bind to custom xml.
Scenario – Generate Sales Contracts on the Server
Imagine a scenario where I'm a developer for a law firm that specializes in writing legal contracts for selling properties. My company uses the same exact template for all our property contracts. The only difference is the data/content contained within the contract. For example, who is selling the property, the address of the property, etc. My company has asked me to write a solution that allows lawyers to easily insert the necessary data into the template without needing to copy/paste the content within the document. An additional request is to have this solution generate the resulting document on the server.
Solution
I am going to base my solution on many of the concepts described in this excellent post from the Word team blog. My solution will take advantage of content controls that are bound to custom xml. In other words, by using bound content controls I will be separating the presentation of my documentation from my data, which will be stored in a separate custom xml part within my Wordprocessing document. Bound content controls allow for the following functionality:
- When a user types into a bound content control, the corresponding data in the custom xml is updated appropriately
- When the data in the custom xml part is updated, the corresponding content control content that is bound to that data is updated appropriately
To accommodate the server requirement I will build this solution on top of ASP.NET. My solution website will contain several form fields, which will represent the data to be inserted in the document. To easily insert this data into my document, I will generate a custom xml file based on this data and then insert this custom xml file into my Wordprocessing package. The content controls that are bound to this custom xml will automatically pull in the appropriate data.
If you just want to jump straight into the code, feel free to download this solution here.
Step 1 – Create a Template
As with my previous posts, the first step is always setting up the right template. In this case, my template will simply be the contract of sales with content controls around the regions in which necessary data needs to be inserted. My template will look like the following:
In addition to demarcating semantic regions, these content controls need to be bound to custom xml. The binding of a content control to an XML element within custom xml is accomplished by specifying the namespace of the custom xml file as well as the XPath expression which uniquely targets the element we wish to bind. Here is an example markup that specifies the binding of a content control:
<w:dataBinding w:prefixMappings="xmlns:ns0='https://contoso.com/2005/contracts/commercialSale' " w:xpath="/ns0:contract[1]/ns0:dateExecuted[1]" w:storeItemID="{ABB284D9-2C5E-41BD-A2F2-B5FC934955A9}"/>
Here are the three main ways to specify content control binding
- Content Control Tool Kit
- This addin to Word makes binding content controls to XML data easy and intuitive. A must have tool
- Use the Word object model
- You can use ContentControl.XMLMapping.SetMapping()
- Directly manipulate the underlying xml
- You can use the SDK to help out here
For my template I will simply bind my content controls to an empty custom xml file. In other words, this custom xml file contains no data. Binding to an empty custom xml file will ensure that just the placeholder texts of the content controls are shown.
Step 2 – Create the ASP.NET Front End Website
The next step is to create a front end website that allows users to insert data to be inserted into the document. For this step I created a simple ASP.NET site that looks like the following:
In the backend of the site I will take all this data and create a custom xml file that will be inserted into my Wordprocessing document.
Step 3 – Replacing Custom XML
Once I have created my custom xml file I now need to insert it into my Wordprocessing document. To accomplish this task I need to open my document and add this custom xml file as a custom xml part. The following code accomplishes these steps:
protected void ReplaceCustomXML(string fileName, string customXML) { using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(fileName, true)) { MainDocumentPart mainPart = wordDoc.MainDocumentPart; mainPart.DeleteParts<CustomXmlPart>(mainPart.CustomXmlParts); //Add a new customXML part and then add content CustomXmlPart customXmlPart = mainPart.AddNewPart<CustomXmlPart>(); //copy the XML into the new part... using (StreamWriter ts = new StreamWriter(customXmlPart.GetStream())) ts.Write(customXML); } } |
Step 4 – Generating the Resulting Document
Once I have created the proper document with all the necessary information I need a way for the user to open or save the file. The following code accomplishes this task:
protected void GenerateContractButton_Click(object sender, EventArgs e) { string strTemp = Environment.GetEnvironmentVariable("temp"); string strFileName = String.Format("{0}\\{1}.dotx", strTemp, Guid.NewGuid().ToString()); File.Copy(Server.MapPath(@"App_Data/Contract of Sale.dotx"), strFileName); GetData(); string customXml = File.ReadAllText(Server.MapPath(@"App_Data/datatemp.xml")); ReplaceCustomXML(strFileName, customXml); //return it to the client - we know strFile is updated, so return it Response.ClearContent(); Response.ClearHeaders(); Response.AddHeader("content-disposition", "attachment; filename=Conract of Sale.dotx"); Response.ContentEncoding = System.Text.Encoding.UTF8; Response.TransmitFile(strFileName); Response.Flush(); Response.Close(); //Delete the temp file File.Delete(strFileName); File.Delete(Server.MapPath(@"App_Data/datatemp.xml")); } |
At this point in time we have generated a document that has content controls bound to all the appropriate data. The resulting file will look like the following:
End Result
In this example scenario I only manipulated the parts within the Wordprocessing document. That means this code is fully functional with version 1 of the Open XML SDK.
Just to show how fast this solution is I attempted to create 100 documents on the server. This code took 1.166 seconds to generate 100 documents. Pretty cool!
Zeyad Rajabi
Comments
Anonymous
January 05, 2009
PingBack from http://blog.a-foton.ru/index.php/2009/01/06/taking-advantage-of-bound-content-controls/Anonymous
January 08, 2009
Brian, Whilst content controls are a good step forward there are still some major parts missing which prevent them being very useful.
- In order to print the customized documents you need to use the word object model. This is unsupported on a server/service.
- To email the documents it makes sense to use a portable format like PDF or XPS. Again you can convert then using the word 2007 object model. So we have the same problem not being able to run on a server/in a service.
- To allow users to design their own templates they need an easy way to add content controls. They should be able to choose fields from a supplied list of fields or schema. Ideally they would also be able to choose from a list of schemas. Currently you cannot do this from word itself which is the obvious environment for the software user.
- It would be useful to be able to supply different data sources, not just XML. I'm thinking in particular of supplying the .Net DataTable class or custom collections programatically as well as other external databases and excel, csv etc.
- For an ISV like ourselves the fact that this is all Office 2007 only is a major stumbling block and will be for a while yet.
- Repeated data lines (like a table) is a pain point. This is not a rant, I'm just trying to illustrate some of the scenarios developers want to achieve. Hopefully future office versions will build on the content control model and the V2 SDK looks quite promising. Finally just to say thanks for taking the time to post this stuff. It is genuinely informative and much appreciated. LJ
Anonymous
January 08, 2009
John, Your feedback is much appreciated. I do agree that Word has room for improvement when it comes to content controls. With respect to your point around repeated data lines, I am planning on writing a post where I leverage the Open XML SDK to accomplish this scenario. Thanks, Zeyad RajabiAnonymous
January 08, 2009
John, So one way to work around some of the content control issues you mentioned is to not only ensure that the content controls are bound to custom xml, but also add the custom xml as cached content. Zeyad RajabiAnonymous
January 08, 2009
En ce début d’année 2009, les personnes étant pour beaucoup en vacances, le web n’a pas regorgé d’uneAnonymous
January 09, 2009
How about a post about generating a document via a website wizard, pulling in data from a SQL back end that allows a user to choose variables. Say automating a Patent application that has 15 different forms from said wizard. We do this in Word now. We want to do it via the web. We haven't been able to using your SDK. You should purchase xpertdoc and learn from them. http://www.xpertdoc.com/en/Default.aspxAnonymous
January 11, 2009
The beauty of MSO is that it is not a "be all - end all" wannabe solution that falls flat on its face when you take one step away from its competence. Instead it is an infinitely extensible application, API, object model and file format conglomerate. Which xpertdoc products readily confirm.Anonymous
January 12, 2009
IT Director, Interesting blog post suggestion. I am planning on writing a couple of blog posts showing how to generate a Word document from data within a database. Stay tuned. Zeyad RajabiAnonymous
January 12, 2009
Hi, my name is Ali and I'm a developer on the Word team. I have been part of the feature team workingAnonymous
January 12, 2009
Man, it's already the second week of 2009. Where does the time go? Here are a few links to posts andAnonymous
January 19, 2009
Hio, very cool Article. But I am searching for an Idea or article which explains "Repeated data lines (like a table)" like John mentioned before. Because I looked about 2 days now and can't find any article about it :-/. I hope you will post some ideas about this soon.