2014-04-03 53 views
0

我試圖修改this example以在未安裝Office的服務器上使用來自數據庫的數據填充Word模板(無Interop)。我希望能夠從數據庫中拉出模板本身,並將生成的填充文檔存儲回數據庫。服務器生成的Word文檔將驗證但不打開

我可以上傳和下載模板文件本身,並且下載的模板仍然可以被Word讀取。但是,當我嘗試使用數據填充模板並下載生成的文檔時,當我嘗試打開文檔時收到以下錯誤:

很抱歉,我們無法打開test.docx,因爲我們發現 的內容存在問題。
詳細信息:提供

自定義XML文檔沒有錯誤的細節,item1.xml似乎是正確的格式,並且包含正確的數據。但是也有一個item2.xml包含以下內容:

<?xml version="1.0"?> 
<b:Sources xmlns="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" 
    xmlns:b="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" Version="6" StyleName="APA" 
    SelectedStyle="\apasixtheditionofficeonline.xsl"/> 

在XML唯一的區別懷疑我能看到的是docProps\app.xml。在模板中有這樣的:

<Template>EquipmentOffering.dotx</Template> 
<TotalTime>950</TotalTime> 
<Pages>5</Pages> 
<Words>2470</Words> 
<Characters>14084</Characters> 
<Application>Microsoft Office Word</Application> 
<DocSecurity>0</DocSecurity> 
<Lines>117</Lines> 
<Paragraphs>33</Paragraphs> 

而生成的文件中我有這樣的:

<Template>EquipmentOffering.dotx</Template> 
<TotalTime>1297</TotalTime> 
<Pages>1</Pages> 
<Words>2486</Words> 
<Characters>14176</Characters> 
<Application>Microsoft Office Word</Application> 
<DocSecurity>0</DocSecurity> 
<Lines>118</Lines> 
<Paragraphs>33</Paragraphs> 

(有明顯更在該文件中,但是這是可疑的部分)

具體,<Pages>元素讓我感到擔憂。

這是我實現的示例代碼:

Private Const strRelRoot As String = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" 

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.myDatabase_dbData.DocTemplates 
         Where sws.TemplateName.Contains("EquipmentOffering") 
         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, create a file package, and extract the relationship collection 
    Using pkgStream As MemoryStream = New MemoryStream(fileBuffer, True) 
     Using pkgFile As Package = Package.Open(pkgStream, FileMode.Open, FileAccess.ReadWrite) 
      Dim pkgrcOfficeDocument As PackageRelationshipCollection = pkgFile.GetRelationshipsByType(strRelRoot) 

      'Scan each relationship looking for custom XML 
      For Each pkgr As PackageRelationship In pkgrcOfficeDocument 
       If (pkgr.SourceUri.OriginalString = "/") Then 

        '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") 
        Using docStream As Stream = pkgprtData.GetStream() 
         Using writer As XmlWriter = XmlWriter.Create(docStream) 

          'Write the root element and our namespace 
          writer.WriteStartDocument() 
          writer.WriteStartElement("Offering", "http://www.acrison.com") 

          'Write in each data element 
          For Each element In params.OfferingData 
           writer.WriteElementString(element.Key, element.Value) 
          Next 

          writer.WriteEndElement() 
          writer.WriteEndDocument() 
         End Using 
        End Using 
       End If 
      Next 

      'Rewind the 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.myDatabase_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.myDatabase_dbData.SaveChanges() 

     End Using 
    End Using 
End Sub 

任何人都看不到任何東西,我做錯了會導致錯位.docx文件?


正如意見中的要求,我創建了一個簡單的三個控制模板,並試圖生成一個文件,該文件出現損壞。 Dropbox鏈接到模板文件並生成Word .docx

我注意到一件奇怪的事情,雖然我這樣做了。試圖在Word 2013中打開.docx導致上述錯誤。但Dropbox可以成功預覽它,儘管內容控件的顯示方式與沒有綁定數據一樣。我不確定這是什麼意思。


通過@Flowerking,並試圖許多例子中的解決方案出來提供的鏈接,看完後,我碰到this來得如此回答使用的Open XML 2.0和這似乎已經工作了的OP。結合我有什麼,有些什麼,我的博客鏈接閱讀,這個問題的答案,我想出了以下內容:

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 

我相信,我只使用正確的Open XML 2.5的方法,但現在的結果是相同,我無法打開生成的.docx。我甚至使用過Open XML SDK 2.5生產力工具,並在Word 2007,2010和2013年生成.docx驗證。

Dropbox中的文檔已更新爲我正在使用的文檔。任何人都可以看到他們的任何錯誤?

+0

不確定未檢查,但.docx等中的itemn.xml文件通常具有關聯的itemPropsn.xml文件以及從一個關係到另一個關係。引用的示例是舊的(2006) - 可能是爲2007版的預發佈版本編寫的,不需要這樣做? –

+0

@bibadia Props文件確實存在。經仔細檢查,我發現它引用了錯誤的模式。但是,使用正確的架構上傳模板的最新副本並不能解決問題。 –

+0

我不擔心頁面元素。如果您將docx放置在人們可能爲您診斷它的地方,您將增加解決此問題的可能性。或者,您可以使用Open XML Power Tools將模板與生成的docx進行比較。 – JasonPlutext

回答

0

原來的主要問題是我的模板是.dotx,我將生成的文件保存爲.docx。將生成的文件的擴展名更改爲.dotx我可以打開它並查看內容。

我不確定在SDK中是否有方法進行轉換。但簡單地保存初始模板爲.docx解決了這個問題。

1

我認爲您的代碼適用於支持Word 2007中的自定義XMl零件的舊Open XML。但是,Microsoft丟失了patent case,並且必須從word open xml中刪除自定義xml。

Dropbox正在正確顯示文檔,因爲它將其視爲單詞打開xml 2007格式。您可以簡單地將您的文檔的擴展名從.docx重命名爲.doc,Word可以在沒有錯誤的情況下打開它,但會丟失內容控件中的數據。

最好的解決方案是遵循最新的開放xml規範,而不是使用自定義xml部分。查看this blog以及使用內容控件的一些示例。

希望這會有所幫助。

+0

您的鏈接很有幫助,但我仍然遇到同樣的錯誤。請參閱最新的問題和鏈接文件。讓我知道,如果你看到任何我做錯了關於2007年以後的Word Open XML。 –