2013-08-21 30 views
18

Ho circa 10 documenti di parola che ho generare utilizzando XML aperti e altre cose. Ora vorrei creare un altro documento di Word e uno dopo l'altro mi piacerebbe unirsi a loro in questo documento appena creato. Vorrei utilizzare XML aperto, ogni accenno sarebbe apprezzabile. Qui di seguito è il mio codice:unire più documenti di Word in un 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 (usando 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(); 
     } 

Perché questo codice sovrascrive il contenuto dell'ultimo file quando uso più file? 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()); 
      } 
     } 

Questo codice viene aggiungendo i dati Test2 due volte, in luogo dei dati Test1 pure. Mezzi ottengo:

Test 
Test2 
Test2 

invece di:

Test 
Test1 
Test2 
+2

Come chirs rilevare , stai usando lo stesso Id per tutti gli AltChunk. Devono essere unici. – Flowerking

+1

Ok, è finito ora, grazie per aver mantenuto la pazienza con me. –

+1

Sono felice di vedere che hai finalmente risolto il tuo problema :) Sì, era correlato a Altchunkid. Ho modificato la mia risposta poiché forse non era molto chiara. – Chris

risposta

17

Solo con SDK openXML, è possibile utilizzare l'elemento AltChunk per unire più documenti in uno solo.

Questo collegamento the-easy-way-to-assemble-multiple-word-documents e questo How to Use altChunk for Document Assembly forniscono alcuni campioni.

EDIT 1

In base al codice che utilizza altchunk nel aggiornato domanda (update # 1), ecco il VB.Codice Net Ho testato e che funziona come un fascino per me:

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

La seconda questione (aggiornamento 2 #)

Questo codice è aggiungendo il Test2 dati due volte, al posto dei dati Test1 come bene.

è relativo a altchunkid.

Per ogni documento che si desidera unire nel documento principale, è necessario:

  1. aggiungere un AlternativeFormatImportPart nel mainDocumentPart con una Idche deve essere unico. Questo elemento contiene i dati inseriti
  2. aggiungere nel corpo un elemento Altchunk in cui si imposta il id per fare riferimento allo AlternativeFormatImportPart precedente.

Nel codice, si sta utilizzando lo stesso ID per tutti gli AltChunks. È per questo che vedi più volte lo stesso testo.

io non sono sicuro che l'altchunkid sarà unico con il tuo codice: string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 2);

Se non è necessario impostare un valore specifico, vi consiglio di non impostare in modo esplicito la AltChunkId quando si aggiunge il AlternativeFormatImportPart. Invece, si ottiene uno generato dal SDK in questo modo:

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

Questo non sta facendo quello che voglio fare anche se non c'è nessuna eccezione in arrivo. Sto postando il mio codice aggiornato con Altchunks. –

+0

Devo fare qualcosa anche nel file docx, come aggiungere un altro tipo di segnalibro? –

+1

@ItiTyagi No, nel mio test, ho appena creato due file con un semplice testo (Testo1 e Testo2). E dopo aver eseguito questo codice, il file Test.docx contiene i due paragrafi quando lo apro. – Chris

7

C'è un bel wrapper API (Document Builder 2.2) attorno Open XML appositamente progettato per unire documenti, con la flessibilità di scegliere i punti da unire ecc è possibile scaricarlo dal here.

La documentazione e la schermata getta su come usarlo sono here.

Aggiornamento: Codice di esempio

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

Tipi Source e WmlDocument sono da Document Builder API.

È anche possibile aggiungere i percorsi dei file direttamente se si sceglie di come:

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

Abbiamo trovato questo Nice Comparison tra AltChunk e Document Builder approcci per unire documenti - utile scegliere in base alle esigenze quelli.

È inoltre possibile utilizzare DocX libreria per unire documenti ma preferisco Document Builder su questo per unione di documenti.

Spero che questo aiuti.

+0

C'è un modo per aprire xml attraverso la codifica in quanto questa attività mi sta davvero mangiando, e non posso usare nessun altro strumento, ecc. –

+1

Queste librerie sono wrapper opensource attorno a OpenXml. Document Builder sta usando Open Xml sdk per fare la fusione e non ci sono hard dipendencies. L'unione di documenti non è un compito semplice, insieme al contenuto è necessario migrare stili + altre parti xml aperte senza perdere le relazioni! E questo diventa un incubo quando hai immagini nel documento. Il codice sorgente di Document Builder Api ti darà un'idea dello stesso. – Flowerking

+0

Ho solo bisogno di aggiungere il contenuto, come una pagina, in modo che possa stampare tutto in una volta. –

3

Facile da usare in 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

C'è qualcosa che manca dal codice in questa risposta. – Boric

+0

Cosa stai facendo con lastElem? Sembra essere impostato ma non usato. – Rendition