none
Unable to replace custom xml in template file RRS feed

  • Question

  • Hi,

    I have been partly successful in some instances trying to do this, and quite often unsuccessful. I've been following this walkthrough:

    http://msdn.microsoft.com/en-us/library/ff196606.aspx#Y4471

    to populate a template file which has content controls in it.

    I have created the Word template file, and used the VBA editor to bind custom xml to the document successfully. However, when I run a asp.net sub from an aspx page, to replace the xml part of the document with data from a database, the content does not get replaced. Instead, the document opens up in Word, but it just shows the sample data that is in the original xml file. Can anyone see what I'm doing wrong? Thanks

    This is the code:

    Protected Sub lbPensionIllustration_Click(ByVal sender As Object, ByVal e As EventArgs) Handles lbPensionIllustration.Click
        Const TemplateFile As String = "~/Documents/Financial/Pension/PensionIllustration.docx"
        CreateDocument(TemplateFile)
      End Sub
    
      Private Const strRelRoot As String = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
    
      Private Sub CreateDocument(ByVal TemplateFilePath As String)
        ' Read the file into memory
        Dim buffer() As Byte = File.ReadAllBytes(Server.MapPath(TemplateFilePath))
        Dim memoryStream As MemoryStream = New MemoryStream(buffer, True)
        buffer = Nothing
    
        ' Open the document in the stream and replace the custom XML part
        Dim pkgFile As Package = Package.Open(memoryStream, FileMode.Open, FileAccess.ReadWrite)
        Dim pkgrcOfficeDocument As PackageRelationshipCollection = pkgFile.GetRelationshipsByType(strRelRoot)
        For Each pkgr As PackageRelationship In pkgrcOfficeDocument
          If (pkgr.SourceUri.OriginalString = "/") Then
    
            ' Get the root part
            Dim pkgpRoot As PackagePart = pkgFile.GetPart(New Uri(("/" + pkgr.TargetUri.ToString), UriKind.Relative))
    
            ' Add a custom XML part to the package
            Dim uriData As Uri = New Uri("/customXML/item1.xml", UriKind.Relative)
            If pkgFile.PartExists(uriData) Then
    
              ' Delete template "/customXML/item1.xml" part
              pkgFile.DeletePart(uriData)
            End If
    
            ' Load the custom XML data
            Dim pkgprtData As PackagePart = pkgFile.CreatePart(uriData, "application/xml")
    
            'get selected data
            GetData(pkgprtData.GetStream)
    
          End If
        Next
    
        ' Close the file
        pkgFile.Close()
    
        ' Return the result
        Response.ClearContent()
        Response.ClearHeaders()
        Response.AddHeader("content-disposition", "attachment; filename=document.docx")
        Response.ContentEncoding = System.Text.Encoding.UTF8
        memoryStream.WriteTo(Response.OutputStream)
        memoryStream.Close()
        Response.End()
      End Sub
    
      Private Sub GetData(ByVal stream As Stream)
    
        Dim Adapter As New PensionInfoCL()
        Dim Table As StaffDataSet2.PensionInfoDataTable = Adapter.GetPensionInfo(Request.QueryString("AppNo"))
    
        Dim writer As XmlWriter = XmlWriter.Create(stream)
        writer.WriteStartElement("data")
        writer.WriteElementString("name", String.Concat(CType(Table(0).FORENAME, String), " ", CType(Table(0).SURNAME, String)))
        writer.WriteElementString("ninumber", CType(Table(0).NI_Number, String))
        writer.WriteElementString("dateofbirth", CType(Table(0).DATE_OF_BI, String))
    
        Dim _Salary As Single = 0.0
        _Salary = Table(0).HPW * Table(0).HourlyRate * 52
        writer.WriteElementString("salary", CType(String.Format("{0:c}", _Salary), String))
        writer.WriteEndElement()
        writer.Close()
      End Sub
    

    Friday, May 20, 2011 8:08 AM

Answers

  • AFAIK there is a problem with this example, and a number of other examples like it, because the relationship between a Word ContentControl and a Custom XML Part is actually via a "Properties" part. When you delete the Data part, the relationship is destroyed. So you have to (re-)create the relationship. FWIW I do not really understand why the relationship is from the Data to the Properties, when the ContentControl relationship is from the Document to the Properties (how does Word actually find the Data?) but there you go.

    In your code, if you change

        Dim uriData As Uri = New Uri("/customXML/item1.xml", UriKind.Relative)
    
    to
        Dim uriData As Uri = New Uri("/customXML/item1.xml", UriKind.Relative)
    
        Dim uriProps As Uri = New Uri("/customXML/itemProps1.xml", UriKind.Relative)
    
    and change
        GetData(pkgprtData.GetStream)
    
    to
        GetData(pkgprtData.GetStream)
    
    	pkgprtData.CreateRelationship(uriProps, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps")

    it may work.


    Peter Jamieson
    • Marked as answer by Bruce Song Thursday, June 2, 2011 11:51 AM
    Monday, May 23, 2011 1:14 PM
  • The problem, as far as I can make out, was this:

    I create the word doc with the content controls in it.

    I load the Xml doc and bind the controls to the xml fields using the Word VBA editor. Now, I think at this point something unexpected happens, because it mostly doesn't happen but occasionally it does, which is why it was/is an inconsistent problem. Using the Word VBA editor to load and bind the xml content actually created a third CustomXml file. So after binding, if I change the file's extension to .zip and then explore it, if I go to /CustomXml there is item1.xml, item2.xml and item3.xml. item1.xml is blank. item2.xml has the fields you have bound to the content controls, and item3 has the extra stuff that is normally generated at this point.

    What this means is that when I run the .net code to replace the xml content, it does exactly that, but since the code replaces item1.xml, and since the document is bound to item2.xml, the changes aren't reflected in the document.

    What I did to rectify this is to delete all custom xml files in the document using the Word Content Controls Toolkit, rebind the controls to the xml using the same VBA code I used before, check that after having dones this there are only two custom xml files, and hey presto it works. The only snag you might find with this is that if your item1.xml really is totally empty then the Word Content Control toolkit won't pick it up so you won't be able to delete it that way. What I did in this case is just to put some data in it, and then delete it with the Word Content Control Toolkit.

    So I seem to have it working now and I think that's what the problem was in case anyone else out there is having similar troubles

     

    • Marked as answer by iand109 Wednesday, June 22, 2011 9:29 AM
    Wednesday, June 22, 2011 9:29 AM

All replies

  • AFAIK there is a problem with this example, and a number of other examples like it, because the relationship between a Word ContentControl and a Custom XML Part is actually via a "Properties" part. When you delete the Data part, the relationship is destroyed. So you have to (re-)create the relationship. FWIW I do not really understand why the relationship is from the Data to the Properties, when the ContentControl relationship is from the Document to the Properties (how does Word actually find the Data?) but there you go.

    In your code, if you change

        Dim uriData As Uri = New Uri("/customXML/item1.xml", UriKind.Relative)
    
    to
        Dim uriData As Uri = New Uri("/customXML/item1.xml", UriKind.Relative)
    
        Dim uriProps As Uri = New Uri("/customXML/itemProps1.xml", UriKind.Relative)
    
    and change
        GetData(pkgprtData.GetStream)
    
    to
        GetData(pkgprtData.GetStream)
    
    	pkgprtData.CreateRelationship(uriProps, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps")

    it may work.


    Peter Jamieson
    • Marked as answer by Bruce Song Thursday, June 2, 2011 11:51 AM
    Monday, May 23, 2011 1:14 PM
  • Hi,

    thanks for the reply. I did try that but it didn't seem to make any difference.

    Thursday, June 9, 2011 8:28 AM
  • OK,

     1. Can you have a look at what is actually inside your .docx before and after running the code? I am assuming that you are starting with a .docx that already contains content controls that are correctly hooked up to the Custom XML part.

      a. Before, I am expecting that you have the following, among others...

    \customXml\item1.xml

    \customXml\itemProps1.xml

    \customXml\_rels

    \customXml\_rels\item1.xml.rels containing a relationship with target \customXml\itemProps1.xml

    \word\_rels

    \word\_rels\document.xml.rels containing a relationship to target ..\customXml\item1.xml

    (That's what I have following creation of a Custom XML part using VBA, even before I create any content controls or link them)

      b. after, I am expecting the same. If that is what you see, then we'll need to dig a bit deeper.

    2. If you are actually trying to create the Custom XML part and contents from scratch and link it in, e.g. there is no item1.xml, then you will need more code. You will at least need to create itemProps1.xml and the relationship from item1 to itemProps1. But you may also need to create the relationship in \word\_rels\document.xml.rels and make the connection from the content controls to the Custom XML part. It depends on what you are expecting to start with.

     


    Peter Jamieson
    Thursday, June 9, 2011 11:10 AM
  • Hi,

    thanks for the reply. Yes, I have all those files:

    \customXml\item1.xml - this is the xml that is currently bound to the content controls.

    there is also item2.xml which just has this in:

    <b:Sources SelectedStyle="\APA.XSL" StyleName="APA" xmlns:b="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" xmlns="http://schemas.openxmlformats.org/officeDocument/2006/bibliography"></b:Sources>

    Then there is \customXml\itemProps1.xml AND itemProps2.xml

    The \customXml\_rels\item1.xml.rels has this in:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps" Target="itemProps1.xml"/></Relationships>

    and the item2.xml.rels is the same (apart from the target). And all the other ones you mentioned are there also.

    As far as I can see, the structure is identical to those documents that do work using this code.

    thanks

    Friday, June 10, 2011 1:06 PM
  • From what you're saying I would agree that there's nothing obviously different between the "before" and "after" files.

    I doubt if the item2.xml /APA thing is a factor, although at this point I wouldn't rule out anything.

    It would be useful if you could post your "before" and "after" samples somewhere that would allow us to download them. Otherwise, you are welcome to despam my email at

    pjj at pjjnet dot demon dot co dot uk

    , send me your samples, and I'll see if I can spot anything.


    Peter Jamieson
    Friday, June 10, 2011 5:34 PM
  • Hi,

    I re-created the documents from scratch, from a dotx template file, and it seems to be working consistently now. On one instance I did spot an error in my code - I had forgotten to write the

    writer.WriteEndElement()
    writer.Close()

    at the end of the getdata sub(oops!)

    The other instance where it didn't work, I don't know what was wrong with it, but re-creating the document seems to have rectified it.

    Thanks for your help

    Wednesday, June 15, 2011 2:12 PM
  • The problem, as far as I can make out, was this:

    I create the word doc with the content controls in it.

    I load the Xml doc and bind the controls to the xml fields using the Word VBA editor. Now, I think at this point something unexpected happens, because it mostly doesn't happen but occasionally it does, which is why it was/is an inconsistent problem. Using the Word VBA editor to load and bind the xml content actually created a third CustomXml file. So after binding, if I change the file's extension to .zip and then explore it, if I go to /CustomXml there is item1.xml, item2.xml and item3.xml. item1.xml is blank. item2.xml has the fields you have bound to the content controls, and item3 has the extra stuff that is normally generated at this point.

    What this means is that when I run the .net code to replace the xml content, it does exactly that, but since the code replaces item1.xml, and since the document is bound to item2.xml, the changes aren't reflected in the document.

    What I did to rectify this is to delete all custom xml files in the document using the Word Content Controls Toolkit, rebind the controls to the xml using the same VBA code I used before, check that after having dones this there are only two custom xml files, and hey presto it works. The only snag you might find with this is that if your item1.xml really is totally empty then the Word Content Control toolkit won't pick it up so you won't be able to delete it that way. What I did in this case is just to put some data in it, and then delete it with the Word Content Control Toolkit.

    So I seem to have it working now and I think that's what the problem was in case anyone else out there is having similar troubles

     

    • Marked as answer by iand109 Wednesday, June 22, 2011 9:29 AM
    Wednesday, June 22, 2011 9:29 AM