📜 ⬆️ ⬇️

TemplateEngine.Docx - OpenSource .NET docx template engine for documents



In the development of corporate applications, it is often necessary to solve the problem of uploading data to documents - from small references to large reports.

I want to share our opensource-solution for generating docx documents, which allows you to fill in documents according to a template, the design of which can be changed in Word without rewriting the code.
')
For a start - a little introductory.

What we needed from the template engine



Searches for template engines


Our search for a suitable "template engine" was not successful: some offer to create a document with a design on the server, the second allows you to replace only static text (for example, https://github.com/swxben/docx-template-engine ), and others do not support nesting ( http://livedocx.com/ ), the fourths add different programmer notation to the template, which we would like to avoid, leaving the template as clean as possible ( https://github.com/tssoft/TsSoft.Docx.TemplateEngine ).

What happened with us


On the code side, we work with familiar entities, such as “Table”, “List”, “String”, and “Cell”.

From the template side, a document is used with Content Controls arranged in it, which are associated with data through the tag property. Content Controls are added quite easily, while it is quite difficult to spoil them during further operation, unlike text insertions like {FIO}, and with the design mode turned off, no special designations of controls are visible.

For example, it is necessary to fill the table, specify the date of its filling and the number of records.
Create a template for this table in a Word document:


Each field that we will fill in must be placed in the control, associated with the data in the code. For this:
  1. Go to the tab “Developer” (if it is absent, turn on through File → Options → Set up ribbon → Put a tick next to “Developer”) and turn on design mode.
  2. Select the text that will be the field to be filled.
  3. Click “Insert content control“ Formatted Text ”.
  4. Click "Properties" and fill in the fields "Name" and "Tag".




If you need to fill a table or list, they also need to be placed in a separate content control.

This is the template with the added content controls:


Now fill the template with the data:
we need to add one field and one table with two rows, and in the table footer specify the number of records.
var valuesToFill = new Content( new FieldContent("Report date", DateTime.Now.Date.ToString()), new TableContent("Team members") .AddRow( new FieldContent("Full name", "  "), new FieldContent("Role", "")) .AddRow( new FieldContent("Full name", "  "), new FieldContent("Role", "")) .AddRow( new FieldContent("Full name", "  "), new FieldContent("Role", " ")), new FieldContent("Count", "3") ); 


We launch TemplateProcessor ...
 using(var outputDocument = new TemplateProcessor("OutputDocument.docx") .SetRemoveContentControls(true)) { outputDocument.FillContent(valuesToFill); outputDocument.SaveChanges(); } 


If everything worked out, the output of the following document:



Using the SetRemoveContentControls (bool value) method, you can remove content controls if they are no longer needed in the resulting document.

TemplateEngine.Docx allows you to fill in simple fields, tables, lists, nested lists, tables with lists, lists with tables, and even lists with tables that have lists ... The Content class structure allows you to create templates with unlimited nesting of elements.



More examples!


Fill simple fields



 var valuesToFill = new Content(new FieldContent("Report date", DateTime.Now.ToString())); 


Filling in the tables



 var valuesToFill = new Content( new TableContent("Team Members Table") .AddRow( new FieldContent("Name", "Eric"), new FieldContent("Role", "Program Manager")) .AddRow( new FieldContent("Name", "Bob"), new FieldContent("Role", "Developer")), new FieldContent("Count", "2")); 


Filling lists



 var valuesToFill = new Content( new ListContent("Team Members List") .AddItem( new FieldContent("Name", "Eric"), new FieldContent("Role", "Program Manager")) .AddItem( new FieldContent("Name", "Bob"), new FieldContent("Role", "Developer"))); 


Filling nested lists



 var valuesToFill = new Content( new ListContent("Team Members Nested List") .AddItem(new ListItemContent("Role", "Program Manager") .AddNestedItem(new FieldContent("Name", "Eric")) .AddNestedItem(new FieldContent("Name", "Ann"))) .AddItem(new ListItemContent("Role", "Developer") .AddNestedItem(new FieldContent("Name", "Bob")) .AddNestedItem(new FieldContent("Name", "Richard")))); 


Table inside the list



 var valuesToFill = new Content( new ListContent("Projects List") .AddItem(new ListItemContent("Project", "Project one") .AddTable(TableContent.Create("Team members") .AddRow( new FieldContent("Name", "Eric"), new FieldContent("Role", "Program Manager")) .AddRow( new FieldContent("Name", "Bob"), new FieldContent("Role", "Developer")))) .AddItem(new ListItemContent("Project", "Project two") .AddTable(TableContent.Create("Team members") .AddRow( new FieldContent("Name", "Eric"), new FieldContent("Role", "Program Manager")))) .AddItem(new ListItemContent("Project", "Project three") .AddTable(TableContent.Create("Team members") .AddRow( new FieldContent("Name", "Bob"), new FieldContent("Role", "Developer"))))); 


List inside the table



 var valuesToFill = new Content( new TableContent("Projects Table") .AddRow( new FieldContent("Name", "Eric"), new FieldContent("Role", "Program Manager"), new ListContent("Projects") .AddItem(new FieldContent("Project", "Project one")) .AddItem(new FieldContent("Project", "Project two"))) .AddRow( new FieldContent("Name", "Bob"), new FieldContent("Role", "Developer"), new ListContent("Projects") .AddItem(new FieldContent("Project", "Project one")) .AddItem(new FieldContent("Project", "Project three")))); 


A table consisting of several blocks that are filled independently



 var valuesToFill = new Content( new TableContent("Team Members Statistics") .AddRow( new FieldContent("Name", "Eric"), new FieldContent("Role", "Program Manager")) .AddRow( new FieldContent("Name", "Richard"), new FieldContent("Role", "Program Manager")) .AddRow( new FieldContent("Name", "Bob"), new FieldContent("Role", "Developer")), new TableContent("Team Members Statistics") .AddRow( new FieldContent("Statistics Role", "Program Manager"), new FieldContent("Statistics Role Count", "2")) .AddRow( new FieldContent("Statistics Role", "Developer"), new FieldContent("Statistics Role Count", "1"))); 


Vertically merged table



 var valuesToFill = new Content( new TableContent("Team members info") .AddRow( new FieldContent("Name", "Eric"), new FieldContent("Role", "Program Manager"), new FieldContent("Age", "37"), new FieldContent("Gender", "Male")) .AddRow( new FieldContent("Name", "Bob"), new FieldContent("Role", "Developer"), new FieldContent("Age", "33"), new FieldContent("Gender", "Male")) .AddRow( new FieldContent("Name", "Ann"), new FieldContent("Role", "Developer"), new FieldContent("Age", "34"), new FieldContent("Gender", "Female"))); 


Table with horizontally merged cells



 var valuesToFill = new Content( new TableContent("Team members projects") .AddRow( new FieldContent("Name", "Eric"), new FieldContent("Role", "Program Manager"), new FieldContent("Age", "37"), new FieldContent("Projects", "Project one, Project two")) .AddRow( new FieldContent("Name", "Bob"), new FieldContent("Role", "Developer"), new FieldContent("Age", "33"), new FieldContent("Projects", "Project one")) .AddRow( new FieldContent("Name", "Ann"), new FieldContent("Role", "Developer"), new FieldContent("Age", "34"), new FieldContent("Projects", "Project two"))); 


Where can I download


The project is available at NuGet ( http://www.nuget.org/packages/TemplateEngine.Docx/ ), and is open to pull requests on GitHub ( https://github.com/UNIT6-open/TemplateEngine.Docx ).

Thank you all for your attention, we hope that this tool will help you in your projects.

Authors: Alexey Volkov, Ruslana Kotova

Source: https://habr.com/ru/post/269307/


All Articles