Introducing Report Templates to Generate Data-Bound Word Documents in C#
As the digital age expands, safely documenting all types of content becomes more important. Digital expansion brings with it a need for simplification. It should be easy to store and create documents that follow regulations and keep private information secure.
In the past, creating these documents involved a template, filled out by hand, or manually on a computer. Files were then saved, or scanned to a digital format for storage. This is not necessarily a bad option for smaller organizations, but it does not scale well.
For enterprise companies such as large ebanks, insurance companies, or investment firms this type of work is time consuming and error prone. It makes more sense to create a structured document with all the fields in place. Then populate it with the actual data and generate the required document automatically by combining a template and data from a database . This structured document is generally referred to as a template and the process of attaching data to it is known as document automation.
As document automation becomes the norm, Developers need to choose a document automation system. The Word API from GrapeCity (GcWord) is an ideal system. With familiar syntax and robust tools, GcWord API for .NET makes implementing document automation quick and easy.
GcWord supports templates in Word. Documents are stored in a central location, then retrieved and populated on-demand. Using the GcWord API, generating data bound Word documents in a .NET application maximizes the effort used to design the layout of the document template. GcWord API for .NET is ideal for businesses that need hundreds or thousands of documents created at once.
This article details the document automation process using GcWord API for .NET. First we create templates in Word. Then we use an application to create and store important files with document automation.
Use Cases for Report Templates
A large regional travel agency needs your help automating the creation of customer itineraries. Although each of the agency’s customers has different information in their itinerary, the document format should remain consistent.
Customers love the accuracy and consistent layout of their itineraries. However, the agency’s business has increased significantly. As business increases the agency can’t keep up. They make errors translating travel plans from orders to itineraries. This causes confusion and angers customers.
Each itinerary must include customer information, flight and hotel booking details, and any activities planned for the vacation. What varies in each document is the customer data but the document structure remains the same. Help the company implement a process that creates accurate, consistent documents quickly. First, design a template with tags. Then process the document using external data, and save the document to the appropriate repository.
Follow the steps below to set up, code, and use this sample application:
Configure .NET Application
- Create a new C# .NET Core Console Application
- Install GrapeCity.Documents.Word package using Nuget package manager in the application
- Add a reference to GrapeCity.Documents.Word namespace in Program.cs file
- Get the sample itinerary template or create one from scratch based on the below image
using GrapeCity.Documents.Word;
Template Design
Create the template using Word. Add the required structural elements such as list, tables, and tags using the Mustache syntax {{ and }}/ for the places that need filled with data.
Create the itinerary template by adding text labels, tables, and appropriate tags corresponding to each text label and in each table cell. Here is a snapshot of the Itinerary template created using Word:
Template Processing in .NET
Create the template and save it in .docx format. Then follow these steps to process the template and generate the document (using C#):
- Initialize GcWordDocument instance and load the Itinerary template into it
GcWordDocument doc = new GcWordDocument();
doc.Load("Resources\\VacationItineraryTemplate.docx");
- Define the data source and add it to the template's data sources using the Add method of GcWord API
//Sample data for Itinerary template
var itineraryData = new[]
{
new {
clientName = "Mark Louis",
clientPhoneNumber = "876-123-7546",
ItineraryStartDate = "01/12/2019",
ItineraryEndDate = "15/12/2019",
flightDetails = new {
arrivalDate = "01/12/2019",
arrivalAirlineName = "British Airways",
arrivalTime = "08:00 AM",
arrivalTerminal = "T1",
departureDate = "15/12/2019",
departureAirlineName = "British Airways",
departureArrivalTime = "10:00 PM",
departureArrivalTerminal = "T2"
},
hotelDetails = new {
checkinTime = "12:00 PM",
hotelName = "Awasi Patagonia",
hotelAddress = "12/13, Block Street",
hotelInclusion = "Cab Service",
checkOutTime = "11:00 AM"
},
activities = new [] {
new { activityDate ="03/12/2019", activityDestination = "Jungle", activity = "Jungle Safari", remarks = "Make sure to carry woolens"},
new { activityDate = "07/12/2019", activityDestination = "Spa Room", activity = "Spa Session", remarks = "Morning would be the best time"},
new { activityDate = "11/12/2019", activityDestination = "Gym Area", activity = "Yoga Session", remarks = "Wear a comfortable attire"} }
}
};
//Add data source for template
doc.DataTemplate.DataSources.Add("ds", itineraryData);
- Invoke the Process method to replace the tags with data while iterating over all data items
doc.DataTemplate.Process();
- Invoke the Save method to save the processed data bound document
doc.Save("TripDetails.docx");
The generated document looks like this:
The example above uses an array data source and table structure element in the template. However, GcWord API for .NET supports a variety of data input sources including databases and flat files. Now that we have seen the API in action, let's dig into the details of creating a Word template to use with the GcWord API .
Template Language Syntax
A template document consists of Word structural elements such as paragraphs, lists, tables, and tags. These elements are replaced with actual data to automatically generate data bound documents. An example of one such document is presented in the section above. Creating a Word document template and adding structural elements to it requires elaboration. Let's dig into the details to better understand how defining tags and elements must work in order to successfully create a template for document automation.
The template tags are defined using the Mustache syntax "{{" and "}}" and can be categorized into the following two categories:
Value Tag
Value tags define placeholders for actual data in the template document. They are replaced by actual data from the data source when processing the template. It is possible to define a single value, or a list of values.
Basic syntax is listed below:
{{ds.value_path}[:formatter1(args1):formatter2(args2):..formatterN(argsN)]}
- ds: user-defined name of data source when adding the data source to the template using GcWord API
- value_path: full dot-delimited path from data source root to the property name
- formatterX (optional): one or more formatting options that process the current value of the tag and change the data representation
Range Tag
When performing data binding, the data source is generally a collection of objects. All of these objects must be rendered to create a meaningful document.
Therefore, a value tag added to the template document must be placed multiple times to render each object in the collection. However, this is not the most efficient way to create a template. There are likely times when a list contains more or less items. Best to plan for flexibility.
Range tags provide flexibility. A range tag is basically one or more value tags enclosed in an open tag and a closed tag. It defines the area in the template layout where data is likely to be repeated and renders all objects associated with the section. If the open and closed tags are not incorporated in the template document, it can lead to unexpected results.
- {{#ds}} or {{#ds.enumerable_path}}: start of a range block
- {{/ds}} or {{/ds.enumerable_path}}: end of a range block
Considering 'ds' is the user-defined name of a data source when adding the data source to the template using GcWord API, enumerable_path is the full dot-delimited path from data source root to the property name.
Short Format Without Datasource
As depicted in the value tag and range tag syntax, when accessing a property or field in the datasource using the dot delimited path, it should begin with the user define datasource name. But this is required only when multiple datasources are associated with the template. When attaching to a single datasource, there is no need to have the datasource name as part of the tag.
For example {{ds.cities.name}} can be referred as {{cities.name}} in short format (but only when other datasources are not present).
For more details refer to the documentation.
The remaining sections of this document make use of these tags to generate different report templates and process them to get the expected documents.
Important Note: Each example below is assuming a single datasource, therefore the short format (as described above) is being used for all template tags.
Features
Batch process multiple rows of data into separate Word (.docx) documents in .NET
For the first example (above), a single customer was processed. However, in the real-world, it is likely there would be multiple customers who needed itinerary's produced. To manage this, the GcWord .NET Word API supports batch processing and generates separate documents for multiple rows of data. This feature is implemented by invoking the BatchProcess method over the report template.
Assuming, we have data for three customers, we can replace the call to Process method with a call to the BatchProcess method and get the desired results of generating three documents one for each customer. Here is the C# sample code:
// produces a document for each root item in the data source collection
int i = 0;
doc.DataTemplate.BatchProcess(() =>
{
doc.Save($"sample-result-{++i}.docx");
});
Here is quick look at the generated documents:
DataSource Support
The examples up to now have all had static, "in code" data sources. However, the GcWord .NET Word API lets you bind data to Word templates from any data source if the data can be placed in the following objects in code:
- DataSet
- DataTable
- IEnumerable objects Refer to the table below to understand what type of template structure needs to be defined for each type of datasource and what will be the result after processing the template:
Sample Data | Template Syntax | Word Template Snapshot | Data binding results |
DataSetData.txt |
[Table name].[Column name] | ||
DataTableData.txt | [Column name] | ||
ObjectArrayData.txt | [Field name] | ||
ObjectListData.txt | [Field name] |
Help
Lists
Lists are created dynamically by using datasources along with standard Word list types (as noted below). The GcWord .NET Word API has intelligence built in to know, based on the bullet type selected in the template, that it needs to iterate through the datasource referenced in the template to create the list. See the table below to for a visual example of how this works. In other words, there is no need to iterate within code to create separate bullet points in a Word document. The GcWord API along with the template language understands this to be true since the datasource is part of a bulleted list. The different types of lists supported by GcWord templates are:
- Bullet Lists
- Numbered Lists
- Multilevel Lists
Refer to the table below to understand what type of template structure needs to be defined for each type of list and what will be the result after processing the template:
Sample Data | Word Template Snapshot | Data binding results |
BulletListData.txt |
|
|
NumberedListData.txt |
|
|
MultilevelListData.txt |
|
|
The examples above use array data source, you can use datatable or other sources in a similar manner.
Help | Demo
Tables
To use a template for generating a table using data binding create a new Word document, add a table with the required number of columns and two rows (if you want to specify the header row information), or a single row if you don't need headers. Choose an appropriate table style to render the header row and banded rows. If you are rendering the header row, you should specify tags in each cell of the second row to bind each column to specific property or field in the datasource. The template engine is smart enough to understand the datasource object structure and iterate over the collection to generate table with multiple rows.
Here is a quick example of creating a table using an array data source
Sample Data | Template Syntax | Word Template Snapshot | Data binding results |
TableData.txt | [Field name] |
Repeat multiple table rows
Besides the ability to render one row per each source object in the datasource, GcWord .NET Word API can also render multiple table rows for each source object, then repeat this structure for the remaining objects.
Here is an example for rending Order information in two rows, with the first row displaying the Supplier and Category fields, while the second row lists the products supplied from the same source object.
Sample Data | Template Syntax | Word Template Snapshot | Data binding results |
RepeatRowData.txt | [Field name] |
Help | Demo
Loops and Nesting Data
All the previous examples have been simple by design. However, the GcWord API template engine is much more powerful and can generate complex templated documents, including nested collections of data from a datasoure. For Example, consider generating monthly order summaries for each customer. Each summary would need to elaborate on the orders placed to include data like date of the order, products ordered, and which suppliers were involved in fulfilling the order.
The table below shows an example of the nested datasource and template for generating the report, followed by an example of a data bound report generated for one customer:
Sample Data | Word Template Snapshot | Data binding results |
LoopsNestingData.txt |
Help | Demo
Conditionally hide blocks of data
The template document structure containing tags, where datasource objects are populated is call a range, such as a table row or list of items. Each table row or list item generated after repeating the template range and populating the tags with data is referred to as a block. The template engine provides a way to format these blocks to hide them based on specific criteria. The formatting is applied on a tag in the range by passing a parameter to the formatter. The parameter defines the value comparison which the engine uses to decide whether the block is hidden or visible. If the current value of a tag is equal to a value of the parameter, then the engine finds the closest collapsible block and hides it, such as a table row, a list item or an arbitrary section.
Here is a list of all the hide formatters and their short version supported by GcWord .NET Word API template engine, you can use either of these when creating a template.
Hide Formatter | Short Version |
|
|
The table below has examples for hiding each of type of block using a specific hide formatter to help understand the feature better:
Table Row | List Item | Arbitrary Section | |
Sample Data | When listing products of different categories in a table, we would like to hide table rows displaying products from a specific category such as Beverages. Here is the sample data: HideRowList.txt | When listing products of different categories, we would like to hide list items displaying products from a specific category such as Beverages. Here is the sample data: HideRowList.txt | When describing products of different categories in a document using a border less table cell, we would like to hide the section occurrence displaying products from a specific category such as Beverages. Here is the sample data: HideDocSection.txt |
Template Snapshot |
|
{{#ds}}{{Category}} {{Products}:hide-block-if-empty()} ProductId: {{Products.ProductId}} ProductName: {{Products.ProductName}} ProductPrice: {{Products.ProductPrice}} {{/Products}}{{/ds}} |
|
Data binding results |
|
Condiments Product Id: 10000456 Product Name: Aniseed Syrup Product Price: 30 Condiments Product Id: 10000321 Product Name: Northwoods Cranberry Sauce Product Price: 60 Condiments Product Id: 10000654 Product Name: Ikura Product Price: 70 Seafood Product Id: 10000987 Product Name: Knobu Product Price: 40 Seafood Product Id: 10000546 Product Name: Grandma's Boysenberry Spread Product Price: 80 Condiments |
Help
Data Formatters
Within the GcWord .NET Word API, formatting of text and overall document controls are done through what are called "Formatters". These formatters are used to format a tag value when the tag is populated with data. For example, converting a string to upper or lower case, formatting the date to a short string etc.
The tables below list different types of formatters supported by GcWord template engine and portrays an example of each:
Value Formatters | String Formatters | Date Formatters | Array Formatters |
|
|
|
|
Time Formatters | Image and Link Formatters | Collection Formatters |
|
|
|
Here are a few examples showcasing the use of above formatters:
Sample Data | Template Structure | Formatting result |
{ CName= "Villy Smith"} | {{CName}:substring(6)} | Smith |
{ cities = new[] {name = "China"}}; | {{cities.name}:toupper()} | CHINA |
For more details on these formatters please refer to the documentation.
Chained formatters
The formatters can be chained and applied to a tag value, where in the result of one formatter might be the input for another formatter. For example, the following chained formatter will hide all records in a list or table, where UnitPrice is less than 30, formatting the included values as currency:
\{{UnitPrice}:hbi-less(30):format(C)}
or
\{{UnitPrice}:hide-block-if-less(30):format(C)}
Help | Demo
Word Documents (.docx) you can generate using GcWord templates in .NET
With the template engine in GcWord .NET Word API, the sky is the limit with what can be created. Look at the examples below of documents created by the GcWord templating process:
Lease Agreement
View Demo
Consulting Agreement
View Demo
Rental Agreement
View Demo
Employment Contract
View Demo
Happy coding, and remember you can use our online demos and documentation or detailed implementation of these scenarios in a .NET application. Feel free to experiment with this new feature and send us your feedback!