During the merge process, when the Mail
╰ DocumentServer Namespace
╰ MailMerge Class
The MailMerge class is a .NET component that can be used to effortlessly merge template documents with database content in .NET projects, such as ASP.NET web applications, web services or Windows services. class merges JSON or other data into templates, field names are matched against available columns of data in the data source. Hierarchical data structures are merged into repeating merge blocks on the basis of their names.
Mail merge describes the process of creating documents based on templates containing static content and variable elements that are merged from different data sources.
Data Source
To understand the motivation behind the task of renaming hierarchical names in a template, we need to understand the logical structure of the data source and the template. A typical hierarchical data source is shown in the following diagram.
The following screenshot shows a template that accesses fields in different ways.
Accessing Child Tables
company_name comes directly from the root table, while the address comes from a child table. These fields can be accessed using dot notation. For example, to access the street, the merge field name is address.street.
The Contacts part contains a merge block (shown in red below) to list all contacts. A merge block repeats all elements that are part of the block based on the data for that block. In this case, the block includes a soft break and the tab character so that all contacts are listed at the same indent position:
The following animation shows the header section before the merge process and after the merge process:
Repeating Blocks
The detail section lists all orders and their articles. Therefore, two nested merge blocks are inserted. The outer block repeats the orders objects and the inner block lists all articles:
As can be seen in the following animation, the outer block is getting repeated 2 times based on the actual data in the given JSON. The inner table row is defined as the nested block articles and contains all line items:
Renaming Hierarchical Values
If the data source is changed, the merge block names and any fields that use dot notation with these changed names must be updated to match the new data source. In the user interface, this can be done by using the dialog that is provided.
However, this can be automated by programmatically changing the names when hundreds or thousands of templates are changed.
There are two steps that are required to change the name of a table:
- Change the name of merge blocks.
- Change the included table names of merge fields.
Merge blocks are essentially Sub
╰ TXTextControl Namespace
╰ SubTextPart Class
A SubTextPart object represents a user-defined part of a TX Text Control document. with a special prefix txmb_.
private static void RenameMergeBlocks(SubTextPartCollection subTextParts, | |
string oldColumnName, | |
string newColumnName) | |
{ | |
// iterate through all SubTextParts | |
foreach (SubTextPart subTextPart in subTextParts) | |
{ | |
// check if the SubTextPart is a merge block | |
if (subTextPart.Name == "txmb_" + oldColumnName) | |
{ | |
// rename the SubTextPart | |
subTextPart.Name = "txmb_" + newColumnName; | |
} | |
} | |
} |
So we can just loop through all the SubTextParts and change the name after the prefix.
For merge fields, we do essentially the same thing, replacing the full string of the name. This will also refactor fields that contain a table name using dot notation.
private static void RenameMergeFields(ApplicationFieldCollection applicationFields, | |
string oldColumnName, | |
string newColumnName) | |
{ | |
// iterate through all ApplicationFields | |
foreach (ApplicationField applicationField in applicationFields) | |
{ | |
// check if the ApplicationField is a merge field and contains the old column name | |
if (applicationField.TypeName == "MERGEFIELD" && | |
applicationField.Name.Contains(oldColumnName)) | |
{ | |
// create a new MergeField object and replace the old column name with the new column name | |
MergeField mergeField = new MergeField(applicationField); | |
mergeField.Name = mergeField.Name.Replace(oldColumnName, newColumnName); | |
} | |
} | |
} |
The complete helper class is shown below:
using TXTextControl.DocumentServer.Fields; | |
namespace TXTextControl.DocumentServer.DataSources | |
{ | |
public static class Refactor | |
{ | |
public static void RenameDataColumn(TextControl textControl, | |
string oldColumnName, | |
string newColumnName) | |
{ | |
// iterate through all TextParts | |
foreach (TextPartBase textPart in textControl.TextParts) | |
{ | |
RenameMergeBlocks(textPart.SubTextParts, oldColumnName, newColumnName); | |
RenameMergeFields(textPart.ApplicationFields, oldColumnName, newColumnName); | |
} | |
} | |
private static void RenameMergeBlocks(SubTextPartCollection subTextParts, | |
string oldColumnName, | |
string newColumnName) | |
{ | |
// iterate through all SubTextParts | |
foreach (SubTextPart subTextPart in subTextParts) | |
{ | |
// check if the SubTextPart is a merge block | |
if (subTextPart.Name == "txmb_" + oldColumnName) | |
{ | |
// rename the SubTextPart | |
subTextPart.Name = "txmb_" + newColumnName; | |
} | |
} | |
} | |
private static void RenameMergeFields(ApplicationFieldCollection applicationFields, | |
string oldColumnName, | |
string newColumnName) | |
{ | |
// iterate through all ApplicationFields | |
foreach (ApplicationField applicationField in applicationFields) | |
{ | |
// check if the ApplicationField is a merge field and contains the old column name | |
if (applicationField.TypeName == "MERGEFIELD" && | |
applicationField.Name.Contains(oldColumnName)) | |
{ | |
// create a new MergeField object and replace the old column name with the new column name | |
MergeField mergeField = new MergeField(applicationField); | |
mergeField.Name = mergeField.Name.Replace(oldColumnName, newColumnName); | |
} | |
} | |
} | |
} | |
} |
To change all merge blocks and field names from Sales_SalesOrderDetail to New_SalesOrderDetail, the following call can be used by passing the strings and an instance of Server
╰ TXTextControl Namespace
╰ ServerTextControl Class
The ServerTextControl class implements a component that provide high-level text processing features for server-based applications. to the RenameDataColumn method.
TXTextControl.DocumentServer.DataSources.Refactor.RenameDataColumn( | |
textControl1, "Sales_SalesOrderDetail", "New_Sales_SalesOrderDetail"); |