During the merge process, when the MailMerge 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 SubTextParts 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 ServerTextControl to the RenameDataColumn method. TXTextControl.DocumentServer.DataSources.Refactor.RenameDataColumn( textControl1, "Sales_SalesOrderDetail", "New_Sales_SalesOrderDetail");