将多个word文档合并为一个Open Xml

我有大约10个word文档,我使用open xml和其他东西生成。 现在我想创建另一个word文档,我想逐个加入到这个新创建的文档中。 我想使用open xml,任何提示都会很明显。 以下是我的代码:

private void CreateSampleWordDocument() { //string sourceFile = Path.Combine("D:\\GeneralLetter.dot"); //string destinationFile = Path.Combine("D:\\New.doc"); string sourceFile = Path.Combine("D:\\GeneralWelcomeLetter.docx"); string destinationFile = Path.Combine("D:\\New.docx"); try { // Create a copy of the template file and open the copy //File.Copy(sourceFile, destinationFile, true); using (WordprocessingDocument document = WordprocessingDocument.Open(destinationFile, true)) { // Change the document type to Document document.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document); //Get the Main Part of the document MainDocumentPart mainPart = document.MainDocumentPart; mainPart.Document.Save(); } } catch { } } 

更新(使用AltChunks):

 using (WordprocessingDocument myDoc = WordprocessingDocument.Open("D:\\Test.docx", true)) { string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 2) ; MainDocumentPart mainPart = myDoc.MainDocumentPart; AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart( AlternativeFormatImportPartType.WordprocessingML, altChunkId); using (FileStream fileStream = File.Open("D:\\Test1.docx", FileMode.Open)) chunk.FeedData(fileStream); AltChunk altChunk = new AltChunk(); altChunk.Id = altChunkId; mainPart.Document .Body .InsertAfter(altChunk, mainPart.Document.Body.Elements().Last()); mainPart.Document.Save(); } 

当我使用多个文件时,为什么此代码会覆盖最后一个文件的内容? 更新2:

  using (WordprocessingDocument myDoc = WordprocessingDocument.Open("D:\\Test.docx", true)) { MainDocumentPart mainPart = myDoc.MainDocumentPart; string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 3); AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML, altChunkId); using (FileStream fileStream = File.Open("d:\\Test1.docx", FileMode.Open)) { chunk.FeedData(fileStream); AltChunk altChunk = new AltChunk(); altChunk.Id = altChunkId; mainPart.Document .Body .InsertAfter(altChunk, mainPart.Document.Body .Elements().Last()); mainPart.Document.Save(); } using (FileStream fileStream = File.Open("d:\\Test2.docx", FileMode.Open)) { chunk.FeedData(fileStream); AltChunk altChunk = new AltChunk(); altChunk.Id = altChunkId; mainPart.Document .Body .InsertAfter(altChunk, mainPart.Document.Body .Elements().Last()); } using (FileStream fileStream = File.Open("d:\\Test3.docx", FileMode.Open)) { chunk.FeedData(fileStream); AltChunk altChunk = new AltChunk(); altChunk.Id = altChunkId; mainPart.Document .Body .InsertAfter(altChunk, mainPart.Document.Body .Elements().Last()); } } 

此代码将Test2数据附加两次,代替Test1数据。 意思是我得到:

 Test Test2 Test2 

代替 :

 Test Test1 Test2 

仅使用openXML SDK,您可以使用AltChunk元素将多个文档合并为一个。

这个链接易于组装多个单词文档和这个如何使用altChunk进行文档组装提供了一些示例。

编辑1

根据您在更新的问题(更新#1)中使用altchunk的代码,这是我测试过的VB.Net代码,对我来说就像一个魅力:

 Using myDoc = DocumentFormat.OpenXml.Packaging.WordprocessingDocument.Open("D:\\Test.docx", True) Dim altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 2) Dim mainPart = myDoc.MainDocumentPart Dim chunk = mainPart.AddAlternativeFormatImportPart( DocumentFormat.OpenXml.Packaging.AlternativeFormatImportPartType.WordprocessingML, altChunkId) Using fileStream As IO.FileStream = IO.File.Open("D:\\Test1.docx", IO.FileMode.Open) chunk.FeedData(fileStream) End Using Dim altChunk = New DocumentFormat.OpenXml.Wordprocessing.AltChunk() altChunk.Id = altChunkId mainPart.Document.Body.InsertAfter(altChunk, mainPart.Document.Body.Elements(Of DocumentFormat.OpenXml.Wordprocessing.Paragraph).Last()) mainPart.Document.Save() End Using 

编辑2

第二个问题(更新#2)

此代码将Test2数据附加两次,代替Test1数据。

altchunkid有关。

对于要在主文档中合并的每个文档,您需要:

  1. mainDocumentPart添加一个AlternativeFormatImportPart ,其Id 必须是唯一的。 此元素包含插入的数据
  2. 在主体中添加一个Altchunk元素,在其中设置id以引用前面的AlternativeFormatImportPart

在您的代码中,您对所有AltChunks使用相同的Id。 这就是为什么你看到很多时间相同的文字。

我不确定altchunkid对你的代码是唯一的: string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 2);

如果您不需要设置特定值,我建议您在添加AlternativeFormatImportPart时不要显式设置AltChunkId 。 而是由SDK生成一个这样的:

VB.Net

 Dim chunk As AlternativeFormatImportPart = mainPart.AddAlternativeFormatImportPart(DocumentFormat.OpenXml.Packaging.AlternativeFormatImportPartType.WordprocessingML) Dim altchunkid As String = mainPart.GetIdOfPart(chunk) 

C#

 AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(DocumentFormat.OpenXml.Packaging.AlternativeFormatImportPartType.WordprocessingML); string altchunkid = mainPart.GetIdOfPart(chunk); 

有一个很好的包装API(Document Builder 2.2)围绕open xml专门设计用于合并文档,可灵活选择要合并的段落等。您可以从这里下载(更新:移动到github )。

这里有关于如何使用它的文档和屏幕。

更新:代码示例

  var sources = new List(); //Document Streams (File Streams) of the documents to be merged. foreach (var stream in documentstreams) { var tempms = new MemoryStream(); stream.CopyTo(tempms); sources.Add(new Source(new WmlDocument(stream.Length.ToString(), tempms), true)); } var mergedDoc = DocumentBuilder.BuildDocument(sources); mergedDoc.SaveAs(@"C:\TargetFilePath"); 

类型SourceWmlDocument来自Document Builder API。

如果您选择以下情况,您甚至可以直接添加文件路径:

 sources.Add(new Source(new WmlDocument(@"C:\FileToBeMerged1.docx")); sources.Add(new Source(new WmlDocument(@"C:\FileToBeMerged2.docx")); 

AltChunkDocument Builder方法之间找到AltChunk Document Builder 比较 – 有助于根据需求进行选择。

您也可以使用DocX库来合并文档,但我更喜欢使用Document Builder来合并文档。

希望这可以帮助。

易于在C#中使用:

 using System; using System.IO; using System.Linq; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; namespace WordMergeProject { public class Program { private static void Main(string[] args) { byte[] word1 = File.ReadAllBytes(@"..\..\word1.docx"); byte[] word2 = File.ReadAllBytes(@"..\..\word2.docx"); byte[] result = Merge(word1, word2); File.WriteAllBytes(@"..\..\word3.docx", result); } private static byte[] Merge(byte[] dest, byte[] src) { string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString(); var memoryStreamDest = new MemoryStream(); memoryStreamDest.Write(dest, 0, dest.Length); memoryStreamDest.Seek(0, SeekOrigin.Begin); var memoryStreamSrc = new MemoryStream(src); using (WordprocessingDocument doc = WordprocessingDocument.Open(memoryStreamDest, true)) { MainDocumentPart mainPart = doc.MainDocumentPart; AlternativeFormatImportPart altPart = mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML, altChunkId); altPart.FeedData(memoryStreamSrc); var altChunk = new AltChunk(); altChunk.Id = altChunkId; OpenXmlElement lastElem = mainPart.Document.Body.Elements().LastOrDefault(); if(lastElem == null) { lastElem = mainPart.Document.Body.Elements().Last(); } //Page Brake einfügen Paragraph pageBreakP = new Paragraph(); Run pageBreakR = new Run(); Break pageBreakBr = new Break() { Type = BreakValues.Page }; pageBreakP.Append(pageBreakR); pageBreakR.Append(pageBreakBr); return memoryStreamDest.ToArray(); } } }