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.
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.
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:
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.
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='http://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
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.
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.
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:
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:
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:
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