Products Technologies Demo Docs Blog Support Company

Generating Hierarchical Tables from JSON Data in .NET C#

Using TX Text Control, you can generate complex hierarchical tables directly from JSON data. This article explains the code and logic behind it.

Generating Hierarchical Tables from JSON Data in .NET C#

Hierarchical tables can be easily merged using repeating merge blocks with the MailMerge class. But what if the tables are very dynamic with a variable number of columns?

In this case, tables can be dynamically generated using the TX Text Control API by adding nested tables. This method can also be mixed with the MailMerge process by adding a placeholder in your template that will be replaced with the dynamically generated table.

JSON Data

Consider the following JSON data that should be used to generate the table.

[
  {
    "Row": 1,
    "UniqueID": "900-0315918-000",
    "Name": "Tim Typer",
    "Address": "1 Text Control Dr.",
    "City": "Charlotte",
    "Zip": "28209",
    "State": "NC",
    "Country": "US",
    "line_items": [
      {
        "Name": "TX Text Control",
        "Description": "Awesome Document Processor",
        "Price": 2998.00,
        "Quantity": 1,
        "additional_items": [
          {
            "Name": "TX Barcode .NET for Windows Forms",
            "Description": "Barcode Generator for Windows Forms",
            "Price": 499.00,
            "Quantity": 1
          },
          {
            "Name": "TX Spell .NET for Windows Forms",
            "Description": "Spell Checking for Windows Forms",
            "Price": 499.00,
            "Quantity": 1
          }
        ]
      }
    ]
  },
  {
    "Row": 2,
    "UniqueID": "800-0315918-000",
    "Name": "Kathrina Keyboard",
    "Address": "1 Text Control Dr.",
    "City": "Charlotte",
    "Zip": "28209",
    "State": "NC",
    "Country": "US",
    "line_items": [
      {
        "Name": "TX Text Control",
        "Description": "Awesome Document Processor",
        "Price": 2998.00,
        "Quantity": 1,
        "additional_items": [
          {
            "Name": "TX Barcode .NET for Windows Forms",
            "Description": "Barcode Generator for Windows Forms",
            "Price": 499.00,
            "Quantity": 1
          }
        ]
      }
    ]
  }
]

The data contains three hierarchical levels with two data rows on the first level. The JSON string is loaded and converted into a list of JObject elements returned by the DeserializeObject method of the JsonConvert class (Newtonsoft.Json). The CreateTable method is then called with the created list object.

string json = File.ReadAllText(@"data.json");
var data = JsonConvert.DeserializeObject<List<JObject>>(json);

CreateTable(data);

Recursively Adding Tables

The CreateTable method takes the hierarchical data and creates the tables. It is called recursively based on the current hierarchy level. A new table is added based on the number of columns in the current hierarchy level. For each row of data, a new table row is added and the values are added to the table cell text.

In the case where the data value is an array, a new nested table will be added by making a recursive call to the CreateTable method.

// Create a hierarchical table from a list of JSON objects
private void CreateTable(List<JObject> dataObjects) {

  // Get the number of columns of the first object
  int columns = dataObjects[0].Values().Count();

  // Check if the first object contains an array and reduce the number of columns
  columns -= dataObjects[0].Values().Count(value => value.Type == JTokenType.Array);

  // Add a table with the number of columns
  Table table = AddTableAtInputPosition(1, columns);
  int row = 1;

  // Loop through all objects
  foreach (JObject dataObject in dataObjects) {

    // Check if the row is not the first row and add a new row
    if (row != 1) {
      table.Cells.GetItem(row - 1, 1).Select();
      textControl1.Selection.Start += textControl1.Selection.Length;
      textControl1.Selection.Length = 0;
      textControl1.Selection.Start -= 1;
      // Add a new row after the current row
      table.Rows.Add(TXTextControl.TableAddPosition.After, 1);
      // Set the left text distance to 0 to remove the indent
      table.Rows.GetItem().CellFormat.LeftTextDistance = 0;
      // Split all cells 
      table.SplitCells();
    }

    int col = 1;

    // Loop through all properties of the object
    foreach (var info in dataObject) {

      // Check if the property is an array
      if (dataObject[info.Key].Type == JTokenType.Array) {

        textControl1.Selection.Start = table.Cells.GetItem(row, 1).Start;
        table.Rows.Add(TXTextControl.TableAddPosition.After, 1);

        // Set the left text distance to indent the nested table
        table.Rows.GetItem().CellFormat.LeftTextDistance = 600;

        // Select the new row and merge all cells
        table.Select(row + 1, 1, row + 1, table.Columns.Count);
        table.MergeCells();

        // Create a new table for the array
        List<JObject> subObject =
          dataObject[info.Key]?.Select(x => x as JObject).ToList();

        // recursively call the method to create a new nested table
        if (subObject != null) {
          CreateTable(subObject);
          row++;
        }
      }
      else { // Add the value to the table cell
        table.Cells.GetItem(row, col).Text = info.Value?.ToString();
        col++;
      }

    }

    row++;
  }
}

// Add a table at the current input position and return the table object
private Table AddTableAtInputPosition(int rows, int columns) {
  textControl1.Tables.Add(rows, columns);
  textControl1.Selection.Start -= 1;
  return textControl1.Tables.GetItem();
}

Sample Data Results

When this method is called with the sample data, the following table structure will be created.

Creating tables with TX Text Control

Stay in the loop!

Subscribe to the newsletter to receive the latest updates.

Related Posts

ASP.NETWindows FormsWPF

Inserting MergeBlocks with the DataSourceManager and Applying Table Styles in C#

This article shows how to insert MergeBlocks with the DataSourceManager and how to apply table styles to those tables. The article uses the DocumentServer class to insert MergeBlocks with the…


ASP.NETWindows FormsWPF

Useful Tricks for Working with Tables

When you are working with complex and long tables, it can be useful to know if a table is broken up across multiple pages. These code snippets will help you with various table related tasks.


ASP.NETWindows FormsWPF

Extension Method: Converting Tables to Tabs in C#

When you export documents to formats that don't support tables, such as ANSI text, you can convert those tables to tabs. This article describes how to convert a table object to tabs using a C#…


ASP.NETWindows FormsWPF

Formatting Numbers in Table Cells

Table cell text can be interpreted as plain text or as a number with an associated number format. This article explains how to use this format and gives examples for various string formatters.


ASP.NETWindows FormsWPF

Mail Merge MS Word Office Open XML (DOCX) Templates in C#

TX Text Control's MailMerge engine allows you to perform MS Word compatible mail merge processes in .NET based applications. This article gives an overview of the basic functionality and shows how…