Join word docx documents from a template and replace words
I Need to get the contents of a file word as the template, which contains the content of a text, and some of the handles to change any other data and the template create a one-of another word with the same content, however, replicate, and the appropriate values are changed.
As an example, I have in my document a text containing the following content:
Hello
<NOME>
! Welcome ... Your address<ENDERECO>
.
And then I need to create another unique docx containing something like:
Hello
Fulano 1
! Welcome ... Your addressENDERECO 1
.
HelloFulano 2
! Welcome ... Your addressENDERECO 2
.
HelloFulano 3
! Welcome ... Your addressENDERECO 3
.
Where each line would be at the beginning of a new page.
For this I am trying something (doing a Test) using the plugin DocX installed in project via NuGet.
another way to carry out the process will be welcome!
My example for presenting the problem:
public static void Main(string[] args)
{
var dictionary = new Dictionary<string, string>();
dictionary.Add("Fulano 1", "Endereco 1");
dictionary.Add("Fulano 2", "Endereco 2");
dictionary.Add("Fulano 3", "Endereco 3");
var template = new FileStream("D:\\template.docx", FileMode.Open, FileAccess.Read);
var docs = new List<DocX>();
var x = 0;
foreach (var item in dictionary)
{
x++;
var doc = DocX.Create("D:\\temp_NUM.docx".Replace("NUM", x.ToString()));
doc.ApplyTemplate(template, true);
doc.ReplaceText("<NOME>", item.Key);
doc.ReplaceText("<ENDERECO>", item.Value);
doc.Save();
docs.Add(doc);
}
var newDoc = DocX.Create("D:\\newDoc.docx");
foreach (var doc in docs)
newDoc.InsertDocument(doc);
newDoc.Save();
}
Although you are using a simple data source, built with a Dictionary
, the data source will be from the system database where this is to be implemented.
The files temp_1.docx, temp_2.docx and temp_3.docx are created and the content appears correctly.
But in line newDoc.InsertDocument(doc);
in:
foreach (var doc in docs)
newDoc.InsertDocument(doc);
I get the following error: the sequence does not contain elements . And with this the "merge" is not done.
How can I solve the problem?
4 answers
I would use the office API made available by Microsoft itself, and then:
wordApp = New Microsoft.Office.Interop.Word.Application;
oDoc = New Microsoft.Office.Interop.Word.Document;
oDoc = wordApp.Documents.Open("c:\....");
Take a look at the Microsoft website, you will find everything you need about it.
With this tool you can from adding macros (VB) to doing merge.
Very, very long ago I made a DLL for a personal project ( http://pastebin.com/kDZVhpiz ) that can help you.. do not judge the code kk I was 15 years old yet, but it can serve you as a guide.
There is a discussion on the developer page in which they explain that this method is not good and that it should not be used.
I would leave for another package . This one seemed very promising to me: http://www.nuget.org/packages/TemplateEngine.Docx
Example using the library DocX
.
static void Main(string[] args)
{
string templatePath = @"D:\\template.docx";
string newFile = @"D:\\newDoc.docx";
var template = new FileStream(templatePath, FileMode.Open, FileAccess.Read);
string[] aNomes = { "Fulano1", "Fulano2", "Fulano3" };
string[] aLocais = { "Endereco1", "Endereco2", "Endereco3" };
using (DocX doc = DocX.Create(newFile))
{
doc.ApplyTemplate(template, true);
int items = aNomes.Length;
int x = 0;
string modelo = "";
while (items > x)
{
Paragraph par = doc.InsertParagraph();
par.AppendLine(modelo);
par.InsertPageBreakAfterSelf();
foreach (var p in doc.Paragraphs)
{
if (p.Text.Contains("<NOME>") && (p.Text.Contains("<ENDERECO>")))
{
modelo = p.Text;
p.ReplaceText("<NOME>", aNomes[x]);
p.ReplaceText("<ENDERECO>", aLocais[x]);
x++;
}
}
}
doc.Save();
}
Console.WriteLine("Pressione alguma tecla para sair...");
Console.ReadKey();
}
File structure template.docx :
--> Página 1:
Olá <NOME>! Seja bem vindo... Seu endereço <ENDERECO>.
The newdoc file.docx should look like this:
--> Página 1:
Olá Fulano1! Seja bem vindo ... Seu endereço Endereco1
--> Página 2:
Olá Fulano2! Seja bem vindo ... Seu endereço Endereco2
--> Página 3:
Olá Fulano3! Seja bem vindo ... Seu endereço Endereco3
I believe this should work the way you expect.
This is a simple way I managed to solve the problem:
using Novacode;
using System.Collections.Generic;
using Word = Microsoft.Office.Interop.Word;
public class Program
{
public static void Main(string[] args)
{
var docList = new List<string>();
var templatePath = @"D:\template.docx";
var fakeDAO = new Dictionary<string, string>();
fakeDAO.Add("Fulano 1", "Endereco 1");
fakeDAO.Add("Fulano 2", "Endereco 2");
fakeDAO.Add("Fulano 3", "Endereco 3");
var x = 0;
foreach (var item in fakeDAO) {
x++;
var docFilePath = @"D:\temp_NUM.docx".Replace("NUM", x.ToString());
var doc = DocX.Create(docFilePath);
doc.ApplyTemplate(templatePath);
doc.ReplaceText("<NOME>", item.Key);
doc.ReplaceText("<ENDERECO>", item.Value);
doc.Save();
docList.Add(docFilePath);
}
Merge.DoMerge(@"D:\newFile.docx", docList);
}
}
A Class Go:
...
public static class Merge
{
public static void DoMerge(string newFilePath, List<string> docList)
{
object sectionBreak = Word.WdBreakType.wdSectionBreakNextPage;
Word.Application app = new Word.Application();
try {
var doc = app.Documents.Add();
var selection = app.Selection;
var x = 0;
foreach (var file in docList) {
selection.InsertFile(file);
x++;
if (x < docList.Count)
selection.InsertBreak(ref sectionBreak);
}
doc.SaveAs(newFilePath);
}
finally {
app.Quit();
}
}
}