我尝试调整this example以使用未安装Office的服务器上的数据库中的数据填充Word模板(不使用Interop)。我希望能够从数据库中提取模板,并将生成的填充文档存储回数据库。
我可以上传和下载模板文件本身,下载的模板仍可由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
。我甚至在Word 2007,2010和2013下使用了Open XML SDK 2.5 Productivity Tool和生成的.docx
验证。
Dropbox中的文档已更新为我目前正在使用的文档。任何人都可以看到他们有什么问题吗?
答案 0 :(得分:1)
我认为您的代码对于支持Word 2007中的自定义XMl部分的旧Open XML有效。但是Microsoft丢失了patent case并且必须从word open xml中删除自定义xml。
Dropbox正在正确显示该文档,因为它将其视为单词open xml 2007格式。您可以简单地将文档的扩展名从.docx
重命名为.doc
,然后word可以无错误地打开它,但内容控件中的数据丢失。
最佳解决方案是遵循最新的开放xml规范,而不是使用自定义xml部分。查看this blog,了解有关使用内容控件的一些示例。
希望这会有所帮助。
答案 1 :(得分:0)
主要问题是我的模板是.dotx
,我将生成的文件保存为.docx
。将生成的文件的扩展名更改为.dotx
我可以打开它并查看内容。
我不确定SDK中是否有方法可以进行转换。但只需将初始模板保存为.docx
即可解决问题。