2013-08-21 1 views
18

У меня есть около 10 текстовых документов, которые я генерирую с помощью открытого xml и другого материала. Теперь я хотел бы создать документ другого документа и один за другим, я хотел бы присоединиться к ним в этот вновь созданный документ. Я хочу использовать открытый 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 
     { 
     } 
    } 

Update (с помощью 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(); 
     } 

Почему этот код переписывает содержимое последнего файла, когда я использую несколько файлов? Update 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 дважды, вместо данных test1, а также. Значит я получаю:

Test 
Test2 
Test2 

вместо:

Test 
Test1 
Test2 
+2

Как Chirs указал , вы используете тот же идентификатор для всех файлов AltChunk. Они должны быть уникальными. – Flowerking

+1

Хорошо, теперь это сделано, Спасибо, что поддержали меня со мной. –

+1

Я рад видеть, что вы, наконец, решили свою проблему :) Да, это было связано с Альтчункидом. Я отредактировал свой ответ, так как это, возможно, не очень понятно. – Chris

ответ

17

Используя только OpenXML SDK, вы можете использовать элемент AltChunk, чтобы объединить несколько документов в один.

Эта ссылка the-easy-way-to-assemble-multiple-word-documents и эта How to Use altChunk for Document Assembly предоставляют некоторые образцы.

EDIT 1

на основе кода, который использует altchunk в обновленном вопрос (обновление № 1), вот VB.Чистый код, который я испытал, и работает как шарм для меня:

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 #)

Этот код Добавляя Test2 дважды, вместо данных Test1, как .

связан с altchunkid.

Для каждого документа, который вы хотите объединить в основной документ, вам необходимо:

  1. добавить AlternativeFormatImportPart в mainDocumentPart с Id, который должен быть уникальным. Этот элемент содержит Введенные данные
  2. добавить в тело элемент Altchunk, в котором вы установили id в качестве ссылки на предыдущие AlternativeFormatImportPart.

В вашем коде вы используете тот же идентификатор для всех AltChunks. Именно поэтому вы видите много раз тот же текст.

Я не уверен, что altchunkid будет уникальным с кодом: string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 2);

Если вам не нужно, чтобы установить конкретное значение, я рекомендую вам не установлено явно в AltChunkId при добавлении AlternativeFormatImportPart. Вместо этого, вы получите один порождена 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); 
+0

Это не то, что я хочу сделать, и не возникает никаких исключений. Я отправляю обновленный код с помощью Altchunks. –

+0

Нужно ли что-то делать в файле docx, например, добавлять другие типы закладок? –

+1

@ItiTyagi Нет, в моем тесте я только что создал два файла с простым текстом (Text1 и Text2). И после запуска этого кода, файл Test.docx содержит два абзаца, когда я его открываю. – Chris

7

Существует хорошая обертка API (Document Builder 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"); 

Типы Source и WmlDocument взяты из документа Builder API.

Вы даже можете добавить пути к файлам напрямую, если вы решите, как:

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

Найдены это Nice Comparison между AltChunk и Document Builder подходами к слиянию документов - полезно выбрать в зависимости от требований Ones.

Вы можете также использовать библиотеку DocX для объединения документов, но я предпочитаю Document Builder над этим для слияния документов.

Надеюсь, это поможет.

+0

Есть ли способ открыть xml через кодирование, так как эта задача действительно меня съедает, и я не могу использовать какой-либо другой инструмент и т. Д. –

+1

Эти библиотеки являются оболочками openource вокруг OpenXml. Document Builder использует 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