J'ai environ 10 documents Word que je génère en utilisant open xml et d'autres trucs. Maintenant, je voudrais créer un autre document Word et un par un, je voudrais les joindre à ce document nouvellement créé. Je souhaite utiliser le xml ouvert, tout indice serait appréciable. Voici mon code:
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
{
}
}
Mettre à jour (en utilisant 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();
}
Pourquoi ce code écrase le contenu du dernier fichier lorsque j'utilise plusieurs fichiers? Mise à jour 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());
}
}
Ce code ajoute les données Test2 deux fois, à la place des données Test1 également. Signifie que je reçois:
Test
Test2
Test2
au lieu de :
Test
Test1
Test2
En utilisant le SDK openXML uniquement, vous pouvez utiliser l'élément AltChunk
pour fusionner plusieurs documents en un seul.
Ce lien la manière simple d'assembler plusieurs documents Word et celui-ci Comment utiliser altChunk pour l'assemblage de documents fournissent quelques exemples.
EDIT 1
Basé sur votre code qui utilise altchunk
dans la question mise à jour (mise à jour # 1), voici le code VB.Net que j'ai testé et qui fonctionne comme un charme pour moi:
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
Le deuxième problème (mise à jour # 2)
Ce code ajoute les données Test2 deux fois, à la place des données Test1 également.
est lié à altchunkid
.
Pour chaque document que vous souhaitez fusionner dans le document principal, vous devez:
AlternativeFormatImportPart
dans le mainDocumentPart
avec un Id
qui doit être unique. Cet élément contient les données inséréesAltchunk
dans lequel vous définissez id
pour référencer le précédent AlternativeFormatImportPart
.Dans votre code, vous utilisez le même identifiant pour tous les AltChunks
. C'est pourquoi vous voyez souvent le même texte.
Je ne suis pas sûr que l'altchunkid sera unique avec votre code: string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 2);
Si vous n'avez pas besoin de définir une valeur spécifique, je vous recommande de ne pas définir explicitement le AltChunkId
lorsque vous ajoutez le AlternativeFormatImportPart
. Au lieu de cela, vous en obtenez un généré par le SDK comme ceci:
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);
Il existe une API Nice wrapper (Document Builder 2.2) autour de xml ouvert spécialement conçue pour fusionner des documents, avec la flexibilité de choisir les paragraphes à fusionner, etc. Vous pouvez le télécharger à partir de ici (mise à jour: déplacé vers - github ).
La documentation et les captures d'écran sur la façon de l'utiliser sont ici .
Mise à jour: exemple de code
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");
Les types Source
et WmlDocument
proviennent de l'API Document Builder.
Vous pouvez même ajouter directement les chemins d'accès aux fichiers si vous choisissez comme:
sources.Add(new Source(new WmlDocument(@"C:\FileToBeMerged1.docx"));
sources.Add(new Source(new WmlDocument(@"C:\FileToBeMerged2.docx"));
Trouvé Nice Comparison entre AltChunk
et Document Builder
approches pour fusionner des documents - utile de choisir en fonction de ses exigences.
Vous pouvez également utiliser la bibliothèque DocX pour fusionner des documents, mais je préfère Document Builder à cela pour la fusion de documents.
J'espère que cela t'aides.
Facile à utiliser en 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();
}
}
}
La seule chose qui manque dans ces réponses est la boucle for
.
Pour ceux qui veulent juste le copier/coller:
void MergeInNewFile(string resultFile, IList<string> filenames)
{
using (WordprocessingDocument document = WordprocessingDocument.Create(resultFile, WordprocessingDocumentType.Document))
{
MainDocumentPart mainPart = document.AddMainDocumentPart();
mainPart.Document = new Document(new Body());
foreach (string filename in filenames)
{
AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML);
string altChunkId = mainPart.GetIdOfPart(chunk);
using (FileStream fileStream = File.Open(filename, FileMode.Open))
{
chunk.FeedData(fileStream);
}
AltChunk altChunk = new AltChunk { Id = altChunkId };
mainPart.Document.Body.AppendChild(altChunk);
}
mainPart.Document.Save();
}
}
Tous les crédits vont à Chris et yonexbat