Have you ever wanted to update page number fields or a table of contents within Word documents on the server? The Open XML SDK provides functionality that allows you to easily add or remove content within a Word document. However, as mentioned in the announcement of the Open XML SDK 2.0, the SDK does not provide runtime application behaviors such as layout and recalculation. In order to recalculate a table of contents you need to run some kind of layout engine in order to properly determine pages within a document.
Word Automation Services is designed to handle tasks that require application logic, such as file conversion and layout. As Brian mentioned in a previous post, Open XML and Office Services are really meant to work better together. In this post, I am going to show you how to leverage Word Automation Services to update a table of contents after a document has been modified by the Open XML SDK.
If you want to jump straight into the code, feel free to download the solutions here.
Imagine a scenario where I am working with a group of people to create a book about the solar system. We've divided up the book into separate chapters where each chapter is assigned to a particular author. Once everyone is done authoring their assigned chapter we want to merge all the documents into one final document. In fact, this scenario is very similar to the scenario I talked about in a previous post titled the easy way to assemble multiple Word documents. The big difference is that in this scenario I want to make sure all page references, including the table of contents, are properly set in the final document.
The scenario discussed above requires two actions:
As is the case with many of my previous posts setting up the right template is the most important step in starting Office document solutions. Once we have the template setup, our next task is to come up with an easy way for users to run the document assembly solution. Since this solution will run on SharePoint, we will create a custom action, which users will be able to access right from a drop down menu off of the template document. This custom action will run the code necessary to assemble the document as well as call into Word Automation Services to update fields.
In summary, we will need to take the following actions:
The template will represent the final look of the document we want to create. In this template we will merge a specific chapter in a specific location within the template. We will leverage content controls as an easy mechanism for specifying semantic regions within a document. In other words, content controls allow us to uniquely identify a specific region within a document. Here is a screenshot of the template we will use:
In the example above, we will use the content control named "SolarOverview" to represent the location where the solar system overview document will be merged. The content of the content control, in this case, "Planets/SolareOverview.docx", represents the SharePoint library location of the document to be merged.
The template document will exist in its own SharePoint library, while the chapters of the solar system book will be stored in the Planets SharePoint library:
Note: There is no technical reason to separate the location of the template document from the chapter documents.
There are several ways to provide UI to users to allow them to invoke our document assembly solution. For the sake of this blog post, we are going to create a custom action that can invoke the document assembly solution straight off of the drop down menu for our template document. Here is a screenshot of the custom action we will create:
Notice that this custom action menu has two Assemble Open XML Document commands. The difference between these two commands is that one of the commands will also invoke Word Automation Services to update fields within the document. In order to create a custom action within SharePoint we will need to create our own custom feature. Here is the xml necessary to create such a feature:
Our next task is to define what this feature looks like via the elements.xml file:
The above xml defines two custom actions, called "Assemble Open XML Document" and "Assemble Open XML Document (New)". These commands will direct users to two different ASP.NET urls, which will allow users to specify the name of the merged document. Both urls will contain a text field as well as an Assemble Document button:
The document assembly solution will be invoked via the Assemble Document button command from the ASP.NET url mentioned above. This command will perform the following actions:
The following code snippet accomplishes these actions:
The above code snippet will merge the Open XML documents together and will ensure that all formatting and content are preserved. Here is a screenshot of how the merged document looks like:
That being said, the code snippet will not update your table of contents, as shown below:
Instead of requiring users to manually update their table of contents, we can perform this action automatically with Word Automation Services. That's where our second custom action command will come into play. The second custom action command is exactly the same as our first command except that it will also invoke Word Automation Services. Here is the code snippet for the second custom action command:
As you can see, calling into Word Automation Services is pretty easy; it's only six lines of code!
Using the above code we should end up with a merged document that has an updated table of contents:
I am excited about this solution because it shows you the power of combining the Open XML SDK with Word Automation Services.