none
Server Generated Word Doc will Validate but not Open RRS feed

  • Question

  • I've posted this question over on Stack Overflow but it's not getting a lot of traction. Hopefully I'll have better luck here. I'll leave the progression of my work on the problem there and just post the current details here as the code is rather lengthy.

    I was trying to adapt this example to populate a Word template with data from a database on a server without Office installed (no Interop). I was told that that method is no longer valid due to a patent lawsuit. So I'm currently working from this example instead using the Open XML SDK 2.5.

    What I'm trying to achieve is to be able to pull a template from the database and store the resultant populated document back into the database.

    I can upload and download the template file itself and the downloaded template is still readable by Word. But when I try and populate the template with data and download the resultant document, I receive the following error when I try to open the document:

    We're sorry. We can't open SimpleTest.docx because we found a problem with its contents.
    Details: No error detail available

    Converting to .zip and inspecting the contents, everything looks okay and the expected data has been placed in the correct place. I have even used the Open XML SDK 2.5 Productivity Tool and the generated .docx validates under Word 2007, 2010, and 2013.

    Here is the code I'm using:

    Protected Overrides Sub Execute()
        'Get the parameters and the template to be filled
        Dim params As CreateOfferingParams = Parameters
        Dim serverWorkSpace = Application.Current.CreateDataWorkspace()
        Dim offeringTemps = From sws In serverWorkSpace.aris_dbData.DocTemplates
                            Where sws.TemplateName.Contains("SimpleTest")
                            Select sws
    
        'Open the template and copy it into a local byte array
        Dim myTemplate As DocTemplate = offeringTemps.FirstOrDefault()
        Dim fileBuffer As Byte() = myTemplate.TemplateFile
    
        'Open the file stream in memory and create a document object from it
        'Must be done this way so stream is expandable
        Dim pkgStream As MemoryStream = New MemoryStream
        pkgStream.Write(fileBuffer, 0, fileBuffer.Length)
    
        Using docTemplate As WordprocessingDocument = WordprocessingDocument.Open(pkgStream, True)
            'Create XML string matching custom XML part
            'Extract the main part of the document and replace any custom XML
            Dim mainPart As MainDocumentPart = docTemplate.MainDocumentPart
    
            For Each part As CustomXmlPart In mainPart.CustomXmlParts
                Dim docStream As New MemoryStream
                Dim docWriter As XmlWriter = XmlTextWriter.Create(docStream)
    
                'Write the declaration, root element and our namespace
                docWriter.WriteStartDocument()
                docWriter.WriteStartElement("Offering", "http://www.mycompany.com")
    
                'Write in each data element
                For Each element In params.OfferingData
                    docWriter.WriteElementString(element.Key, element.Value)
                Next
    
                'Close each of the tags and flush the stream
                docWriter.WriteEndElement()
                docWriter.WriteEndDocument()
                docWriter.Flush()
    
                'Rewind the stream and feed it to the custom XML part we are working on
                docStream.Seek(0, SeekOrigin.Begin)
                part.FeedData(docStream)
    
                'Rewind the package stream
                pkgStream.Position = 0
    
                'Copy the modified package into a new byte array
                Dim generatedOffering As Byte() = New Byte((pkgStream.Length) - 1) {}
                Dim i As Integer = 0
                Do While (i < pkgStream.Length)
                    generatedOffering(i) = CType(pkgStream.ReadByte, Byte)
                    i = (i + 1)
                Loop
    
                'Get the appropriate Quote entity so we have somewhere to store the newly generated file
                Dim quoteInfo = From sws In serverWorkSpace.aris_dbData.Quotes
                                Where sws.QuoteID = params.QuoteIDParam
                                Select sws
    
                Dim myQuote As Quote = quoteInfo.FirstOrDefault()
    
                'Store the file in the entity
                myQuote.QuoteOffering = generatedOffering
    
                'Save out the changes
                serverWorkSpace.aris_dbData.SaveChanges()
            Next
        End Using
    End Sub

    Here are Dropbox links to the template file and the generated .docx.

    Can anyone see what I'm doing wrong?

    Friday, April 11, 2014 2:23 PM

Answers

  • Hi Kyle

    Just FWIW both methods you've looked at using should work. The first one isn't affected by the court decision, it just doesn't make use of the SDK. The information in the article to which you link pre-dates the SDK and uses the Packaging namespace directly (that the SDK wraps up for you).

    Indeed, the file extension must match the file type specified in the document, internally. You'll note that Erika's aritcle uses a .docx as a "template" - she uses the term in a misleading manner. It is possible to work from a true template, but your code would need to include changing the file type. Not really a problem, just an extra step.

    Now to your current issue: losing the content controls' mappings to the custom xml part. For background information on how the mapping works, see

    http://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.databinding(v=office.14).aspx

    It's very important that the XML structures of the original document and what you're using to replace it are identical, otherwise the mapping will not work. I just did some testing and FeedData can work correctly.


    Cindy Meister, VSTO/Word MVP, my blog

    Monday, April 14, 2014 6:40 PM
    Moderator

All replies

  • Hi,

    I tried to use OpenXmlPart.FeedData method to replace the XML in an existing custom xml part,It works fine ,I noticed your code, did you open a template file and then save it as document file ?

    I can open this generated file when I modified your generated.docx file as generated.dotx.

    Regards,

    Marvin


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Monday, April 14, 2014 11:20 AM
    Moderator
  • Okay. I didn't realize there was a difference. I can open the file as well by changing the extension. However, the Content Controls do not contain the data that was inserted even though the data is properly placed in the Custom XML part.

    <?xml version="1.0" encoding="UTF-8"?>
    <Offering xmlns="http://www.mycompany.com">
        <QuoteNumber>60007-14</QuoteNumber>
        <Date>4/10/2014</Date>
        <Status>Initial</Status>
    </Offering>

    What else am I missing?

    Monday, April 14, 2014 1:26 PM
  • Hi Kyle

    Just FWIW both methods you've looked at using should work. The first one isn't affected by the court decision, it just doesn't make use of the SDK. The information in the article to which you link pre-dates the SDK and uses the Packaging namespace directly (that the SDK wraps up for you).

    Indeed, the file extension must match the file type specified in the document, internally. You'll note that Erika's aritcle uses a .docx as a "template" - she uses the term in a misleading manner. It is possible to work from a true template, but your code would need to include changing the file type. Not really a problem, just an extra step.

    Now to your current issue: losing the content controls' mappings to the custom xml part. For background information on how the mapping works, see

    http://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.databinding(v=office.14).aspx

    It's very important that the XML structures of the original document and what you're using to replace it are identical, otherwise the mapping will not work. I just did some testing and FeedData can work correctly.


    Cindy Meister, VSTO/Word MVP, my blog

    Monday, April 14, 2014 6:40 PM
    Moderator