2013-08-21 31 views
18

Mam około 10 dokumentów tekstowych, które generuję przy użyciu otwartego xml i innych rzeczy. Teraz chciałbym stworzyć kolejny dokument tekstowy i jeden po drugim chciałbym dołączyć do tego nowo utworzonego dokumentu. Chciałbym użyć otwartego xml, każda wskazówka byłaby znacząca. Poniżej jest mój kod:Scalanie dokumentów zawierających wiele wyrazów w jednym Otwórz 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 (używając 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(); 
     } 

Dlaczego ten kod nadpisuje zawartość pliku ostatnio kiedy używać wielu plików? Aktualizacja 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()); 
      } 
     } 

Ten kod jest dołączenie danych test2 dwukrotnie, zamiast danych Test1 również. Środki uzyskać:

Test 
Test2 
Test2 

zamiast:

Test 
Test1 
Test2 
+2

Jak chirs wskazał , używasz tego samego ID dla wszystkich AltChunk. Muszą być wyjątkowe. – Flowerking

+1

Ok, gotowe, dziękuję za cierpliwość. –

+1

Cieszę się, że w końcu rozwiązałeś swój problem :) Tak, to było związane z Altchunkidem. Edytowałem swoją odpowiedź, ponieważ być może nie było to zbyt jasne. – Chris

Odpowiedz

17

Używając tylko pakietu openXML SDK, można użyć elementu AltChunk do scalenia wielu dokumentów w jeden.

Ten link the-easy-way-to-assemble-multiple-word-documents i ten jeden dostarczają niektóre próbki.

EDIT 1

oparciu o kodzie, który wykorzystuje altchunk w zaktualizowanym pytanie (update # 1), tutaj jest VB.Kod netto Ja testowałem i który działa jak czar dla mnie:

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

Druga kwestia (aktualizacja 2 #)

Ten kod jest dołączenie Przetestuj dane 2 razy, zamiast danych z Test1 jako dobrze: .

jest powiązany z altchunkid.

Dla każdego dokumentu, który chcesz scalić w dokumencie głównym, trzeba:

  1. dodać AlternativeFormatImportPart w mainDocumentPart z Idktóre muszą być unikalne. Ten element zawiera wstawione dane, dodając do wnętrza element Altchunk, w którym ustawiono id w celu odniesienia do poprzedniego AlternativeFormatImportPart.

W kodzie używasz tego samego identyfikatora dla wszystkich AltChunks. Dlatego wiele razy widzisz ten sam tekst.

nie jestem pewien, że altchunkid będzie wyjątkowy z kodem: string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 2);

Jeśli nie trzeba ustawić konkretną wartość, polecam Ci nie jawnie ustawione na AltChunkId podczas dodawania AlternativeFormatImportPart. Zamiast dostać jeden generowane przez SDK jak ten:

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

To nie działa, co chcę robić, nie ma też wyjątku. Publikuję zaktualizowany kod w Altchunks. –

+0

Czy muszę również coś zrobić w pliku docx, np. Dodając typ zakładek do innych działań? –

+1

@ItiTyagi Nie, w moim teście, właśnie utworzyłem dwa pliki z prostym tekstem (Text1 i Text2). Po uruchomieniu tego kodu plik Test.docx zawiera dwa akapity po jego otwarciu. – Chris

7

Jest ładny otoki API (Document Builder 2.2) wokół Open XML specjalnie zaprojektowany do scalania dokumentów, z elastycznością wyborze akapitów scalania itp. Możesz go pobrać z here.

Dokumentacja i ekrany przedstawiające sposób korzystania z nich to here.

Aktualizacja: Przykładowy kod

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"); 

Rodzaje Source i WmlDocument są z dokumentu Builder API.

Można nawet dodać ścieżki plików bezpośrednio, jeśli zdecydujesz się jako:

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

Znaleźliśmy ten Nice Comparison między AltChunk i Document Builder podejść do scalania dokumentów - pomocne przełącz na podstawie wymagań jedynek.

Można również użyć biblioteki DocX do scalania dokumentów, ale wolę nad nią Kreatora dokumentów do scalania dokumentów.

Mam nadzieję, że to pomoże.

+0

Czy istnieje sposób otwierania kodu XML przez kodowanie, ponieważ to zadanie naprawdę mnie zjada, i nie mogę użyć żadnego innego narzędzia itp. –

+1

Te biblioteki są owijkami otwartego źródła wokół OpenXml. Konstruktor dokumentów używa Open Xml SDK do łączenia i nie ma żadnych trudnych zależności. Scalanie dokumentów nie jest prostym zadaniem, wraz z treścią, którą musisz migrować style + inne otwarte części XML bez utraty relacji! I to staje się koszmarem, gdy masz zdjęcia w dokumencie. Kod źródłowy programu Document Builder Api da ci wyobrażenie o tym samym. – Flowerking

+0

Po prostu muszę dołączyć treść jako stronę, dzięki czemu mogę wydrukować za jednym razem. –

3

Łatwy w użyciu w 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

W tej odpowiedzi brakuje czegoś z kodu. – Boric

+0

Co robisz z lastElem? Wydaje się być ustawiony, ale nie jest używany. – Rendition