Search This Blog

Thursday, October 29, 2009

asp.net – modify docx OpenOfficeXML – using content controls

This took me a while to work out, but finally I got it to work.

The Open Office XML documents utilised by Microsoft in Office 2007 are actually zip files that package a number of folders and documents. So to edit these files you need to be able access the contents.

Microsoft provides an SDK for this purpose there is a version 1 and a version 2 (in CTP, at the time of this article).

http://msdn.microsoft.com/en-us/library/bb448854.aspx – version 1

http://msdn.microsoft.com/en-us/library/bb448854(office.14).aspx – version 2

I downloaded version 2.

I built a simple website, added a reference the .net open xml sdk and created the following page and code behind.

Reference to the open xml sdkimage

 

aspx page

 

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="createWordDocTest.aspx.vb" Inherits="createWordDocTest" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Click to write to word" />
    </div>
    </form>
</body>
</html>


code behind



Imports System.IO
Imports System.Xml
Imports DocumentFormat.OpenXml
Imports DocumentFormat.OpenXml.Packaging
Imports DocumentFormat.OpenXml.Wordprocessing
Partial Class createWordDocTest
    Inherits System.Web.UI.Page
    Protected Sub ReplaceCustomXML(ByVal fileName As String, ByVal customXML As String)
        Using wordDoc As WordprocessingDocument = WordprocessingDocument.Open(fileName, True)
            Dim mainPart As MainDocumentPart = wordDoc.MainDocumentPart
            mainPart.DeleteParts(Of CustomXmlPart)(mainPart.CustomXmlParts)
            'Add a new customXML part and then add content
            Dim customXmlPart As CustomXmlPart = mainPart.AddNewPart(Of CustomXmlPart)()
            'copy the XML into the new part...
            Using ts As New StreamWriter(customXmlPart.GetStream())
                ts.Write(customXML)
            End Using
        End Using
    End Sub
    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs)
        Dim strPath As String = "c:\temp"
        Dim strtemplate As String = strPath & "\" & "inputDoc.docx"
        Dim strNewFile As String = strPath & "\outputDoc.docx"
        If System.IO.File.Exists(strtemplate) = True Then
            If System.IO.File.Exists(strNewFile) = True Then
                System.IO.File.Delete(strNewFile)
            End If
            System.IO.File.Copy(strtemplate, strNewFile)
            Dim xmlDoc As New XmlDocument()
            Dim customXML As String = "<root><CustomerName></CustomerName></root>"
            xmlDoc.LoadXml(customXML)
            Dim xmlnode As XmlNodeList = xmlDoc.GetElementsByTagName("CustomerName")
            xmlnode(0).InnerText = "What ever you want to insert"
            customXML = xmlDoc.InnerXml.ToString
            ReplaceCustomXML(strNewFile, customXML)
            Dim doc As WordprocessingDocument = WordprocessingDocument.Open(strNewFile, True)
            Dim mainPart As MainDocumentPart = doc.MainDocumentPart
            mainPart.Document.Save()
            doc.Close()
        End If
    End Sub
End Class


OK, there is still work to do. We are going to use a template document to house a content control which we will find and change the contents of, via a binding with some customXML . The mechanism here is that you will place a content control on the document, then creation a reference (or binding) to a custom XML entity. To change the content control content you will change the custom XML programmatically (via the asp page) and this will change the content control due to the binding.


OK, create a blank document called inputDoc.docx. Now in the ribbon go to the developer tab. (If the tab is not visible go here http://office.microsoft.com/en-au/word/HA101730521033.aspx). And insert a plain text control.


image 


with the new control inserted…


image 


click on properties in the developer tab…


image 


click on properties in the developer 


image 


With the control properties dialog up, enter CustomerName into the Title and Tag fields. Click OK.


So we have now setup our control. Now we need to create the customXML and the relationship between the customXML and the control. Save the document into your c:\temp folder (or to the folder of your choice (remember you will need to modify the example code above)) and save it as “inputDoc.docx”.


Now this can be done manually by going into the docX package creating files in folders and blah blah blah…. However there is an easier way (and I like easy…)


The Word 2007 Content Control Toolkit, you can get it here http://www.codeplex.com/dbe


Once you have downloaded and installed, fire up the program, and open your document, you see something like this


image 


Now we are going to create some custom XML part and bind it to the control. In the bind view on the right, click on the create a new custom XML part, and then click on edit view tab. You should see 


<root>

</root>



Now change this to


<root>

  <CustomerName>


  </CustomerName>


</root>



 



Go to the  bind View tab. Click on the CustomerName entry in the tree, Now select and drag it to the left pane (Content Controls) and over the control you want to create a relationship (in our case the tag CustomerName).



With that done, click save and close the program.



OK, thats it. Fire up your web page and click the button. You should hopefully find that a document called outputDoc.docx has been created alongside inputDoc.docx and has the contents of the control changed to new values.



Note: CustomXML is not supported in the office 2003 compatibility pack so if you are expecting to use this method with some office 2003 users then don’t as it will not work. I found this out to my own annoyance after getting it to work!…



References



http://www.devx.com/dotnet/Article/42221/1954


http://code.msdn.microsoft.com/OOXMLv20CTP/Release/ProjectReleases.aspx?ReleaseId=2080


 

Share/Bookmark

No comments:

Post a Comment