2013-08-21 282 views
18

我有大約10個使用open xml和其他東西生成的word文檔。 現在我想創建另一個word文檔,並且我想逐個將它們加入到這個新創建的文檔中。 我希望使用開放的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<Paragraph>().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<Paragraph>().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<Paragraph>().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<Paragraph>().Last()); 
      } 
     } 

此代碼兩次追加的Test2數據中,代替測試1數據的爲好。 意味着我得到:的

Test 
Test2 
Test2 

代替:

Test 
Test1 
Test2 
+2

像chirs指出相反,你就會得到由SDK這樣產生的一個,所有AltChunk都使用相同的Id。它們必須是唯一的。 – Flowerking

+1

好的,現在完成了,謝謝你保持耐心。 –

+1

我很高興看到你終於解決了你的問題:)是的,它與Altchunkid有關。我編輯了我的答案,因爲它可能不是很清楚。 – Chris

回答

17

使用的OpenXML SDK,您可以使用AltChunk元素的多個文件合併成一個。

此鏈接the-easy-way-to-assemble-multiple-word-documents而這一次How to Use altChunk for Document Assembly提供一些樣品。

編輯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 

EDIT 2

第二個問題(更新2#)

此代碼追加測試2數據兩次,代替Test1數據爲 。

altchunkid有關。

對於要在主文檔中合併的每個文件,你需要:

  1. mainDocumentPartId它必須是唯一的添加AlternativeFormatImportPart此元素包含插入的數據
  2. 在主體中添加一個Altchunk元素,其中您將id設置爲引用先前的AlternativeFormatImportPart

在您的代碼中,所有AltChunks都使用相同的ID。這就是爲什麼你看到很多時間相同的文字。

我不知道該altchunkid將與您的獨特代碼:string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 2);

如果您不需要設置一個特定的值,我建議當您添加AlternativeFormatImportPart你沒有設置明確的AltChunkId

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); 
+0

這不是我想要做的事,也沒有異常來臨。我用Altchunks發佈我的更新代碼。 –

+0

我是否還需要在docx文件中做些什麼,例如添加書籤類型其他操作? –

+1

@ItiTyagi不,在我的測試中,我剛創建了兩個帶有簡單文本(Text1和Text2)的文件。運行此代碼後,打開Test.docx文件時會包含兩個段落。 – Chris

7

有一個很好的封裝API(文檔生成器2.2)圍繞開放XML專門設計的合併文件,與選擇的段落合併的靈活性等等。你可以從here下載它。

的文檔和屏幕蒙上如何使用它是here

更新:代碼示例

var sources = new List<Source>(); 
//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從文件生成器API。

你甚至可以直接,如果你選擇添加文件路徑爲:

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

發現這個Nice ComparisonAltChunkDocument Builder方法之間合併文件 - 有助於選擇基於那些要求。

您也可以使用DocX庫來合併文檔,但我更喜歡使用Document Builder來合併文檔。

希望這會有所幫助。只有

+0

有沒有辦法通過編碼打開XML,因爲這個任務真的是吃我,我不能使用任何其他工具等 –

+1

這些庫是圍繞OpenXml的開源包裝。文檔生成器正在使用Open Xml sdk進行合併,並且沒有硬性依賴關係。合併文檔不是一件簡單的工作,而且您必須遷移樣式+其他打開的xml部分而不會丟失關係!當你在文檔中有圖片時,這會變成一場噩夢。 Document Builder Api的源代碼會給你一個相同的想法。 – Flowerking

+0

我只需要將內容作爲頁面添加,以便一次打印。 –

3

容易在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<AltChunk>().LastOrDefault(); 
      if(lastElem == null) 
      { 
       lastElem = mainPart.Document.Body.Elements<Paragraph>().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(); 
     } 
    } 
} 
+0

此答案中的代碼缺少一些內容。 – Boric

+0

你在用lastElem做什麼?它似乎已經設置,但沒有使用。 – Rendition

相關問題