# Export Document Tables to CSV in .NET C#

> This article shows how to use ServerTextControl to load documents, iterate through table rows and cells, and export document tables as CSV files. The sample handles multiple tables, header rows, custom separators, and nested table limitations.

- **Author:** Bjoern Meyer
- **Published:** 2026-06-19
- **Modified:** 2026-06-19
- **Description:** This article shows how to use ServerTextControl to load documents, iterate through table rows and cells, and export document tables as CSV files. The sample handles multiple tables, header rows, custom separators, and nested table limitations.
- **4 min read** (778 words)
- **Tags:**
  - ASP.NET
  - ASP.NET Core
  - Tables
  - CSV
- **Web URL:** https://www.textcontrol.com/blog/2026/06/19/export-document-tables-to-csv-in-dotnet-csharp/
- **LLMs URL:** https://www.textcontrol.com/blog/2026/06/19/export-document-tables-to-csv-in-dotnet-csharp/llms.txt
- **LLMs-Full URL:** https://www.textcontrol.com/blog/2026/06/19/export-document-tables-to-csv-in-dotnet-csharp/llms-full.txt
- **GitHub Repository:** https://github.com/TextControl/TXTextControl.TableToCSV

---

Tables in business documents often contain valuable structured data: order lists, inventory snapshots, timesheets, reports, and summaries. But that data is not always stored in a database or spreadsheet. Sometimes it is embedded in HTML, DOCX, RTF, or PDF workflows where the document itself is the source of truth.

This sample shows the reverse direction of a typical CSV-to-document workflow. Instead of creating a document table from CSV data, it loads a document with ServerTextControl, iterates through its tables, reads the table cells, and exports the result as CSV files.

> **Table Extraction with ServerTextControl**
> 
> The complete sample is a console application that uses TX Text Control .NET Server to load HTML sample documents and export all top-level document tables as CSV files.

### When Table-to-CSV Export Is Useful

Table-to-CSV conversion is useful whenever document content needs to move into systems that expect flat tabular data. This happens often in business applications where generated documents contain tables that later need to be analyzed, imported, or processed by another system.

Typical examples include:

- Exporting order tables from generated customer documents for import into ERP or reporting systems.
- Extracting inventory or stock tables from operational reports.
- Converting timesheet tables into CSV files for accounting or billing workflows.
- Pulling regional sales summaries from monthly reports for further analysis in Excel, Power BI, or custom dashboards.
- Creating lightweight data exchange files from document templates without requiring users to manually copy and paste table content.

CSV is intentionally simple. It works best for flat tables where each row contains the same kind of data. For this reason, the sample exports document tables only and ignores surrounding text such as headings, paragraphs, and captions.

### Loading Documents with ServerTextControl

The sample uses ServerTextControl as a non-visual document processing component. The document is loaded from an HTML file, but the same pattern can be adapted to other supported document formats.

```
using var serverTextControl = new ServerTextControl();
serverTextControl.Create();

serverTextControl.Load(documentPath, StreamType.HTMLFormat);

var tables = serverTextControl.Tables.Cast<Table>().ToList();
```

After loading the document, the Tables collection gives access to all tables in the main text. Each Table contains row and cell collections that can be used to read the table structure.

### Exporting Several Tables

A CSV file represents one flat table. It has no native concept of multiple independent tables. Because of that, the sample exports each top-level table into its own CSV file.

If a document contains one table, the file name is based on the document name:

```
inventory-with-notes.csv
```

If a document contains multiple tables, each table is written separately:

```
customer-orders-table-1.csv
customer-orders-table-2.csv
```

The exporter filters out nested tables and keeps only top-level tables:

```
var tables = serverTextControl.Tables.Cast<Table>().ToList();
var topLevelTables = tables.Where(table => table.OuterTable is null).ToList();
```

OuterTable is null for top-level tables. This makes it a straightforward way to avoid exporting nested tables as independent CSV files.

### Respecting Header Rows

TX Text Control table rows can be marked as header rows using TableRow.IsHeader. These rows are repeated at the top of each page when a table spans multiple pages.

For CSV export, those rows should appear first. If no row is marked as a header row, the sample simply exports the rows in their document order, which means the physical first row becomes the first CSV row.

```
private static IEnumerable<TableRow> GetRowsInCsvOrder(Table table)
{
    var rows = table.Rows
        .Cast<TableRow>()
        .Where(row => IsExportableRow(table, row))
        .ToList();

    var headerRows = rows.Where(row => row.IsHeader).ToList();

    if (headerRows.Count == 0)
    {
        return rows;
    }

    return headerRows.Concat(rows.Where(row => !row.IsHeader));
}
```

This preserves one or more explicit table header rows without duplicating them.

### Extracting Cell Text

The actual cell extraction loops through the table's cells, filters them by row number, orders them by column number, and reads the TableCell.Text value.

```
private static IEnumerable<TableCell> GetCells(Table table, TableRow row)
{
    return table.Cells
        .Cast<TableCell>()
        .Where(cell => cell.Row == row.Row)
        .OrderBy(cell => cell.Column);
}
```

The sample normalizes line endings and trims cell values before writing them to CSV:

```
private static string NormalizeCellText(string value)
{
    return value
        .Replace("\r\n", "\n", StringComparison.Ordinal)
        .Replace('\r', '\n')
        .Trim();
}
```

### Handling Nested Tables

Nested tables do not map well to CSV. A CSV cell can contain text, but it cannot contain another grid with its own rows and columns in a standard way.

The sample handles nested tables deliberately:

- Nested tables are skipped as separate CSV exports.
- If a top-level table cell contains a nested table, that cell is exported as an empty value.
- A warning is printed to the console.

```
private static bool ContainsNestedTable(TableCell cell, IReadOnlyList<Table> nestedTables)
{
    if (cell.Length <= 0 || nestedTables.Count == 0)
    {
        return false;
    }

    var cellStart = cell.Start;
    var cellEnd = cell.Start + cell.Length;

    return nestedTables
        .SelectMany(table => table.Cells.Cast<TableCell>())
        .Any(nestedCell => nestedCell.Start >= cellStart && nestedCell.Start <= cellEnd);
}
```

This avoids producing misleading CSV data. In production scenarios, another option would be to write nested tables to separate files and store metadata that links them back to the parent cell.

### CSV Formatting and Separators

CSV output must escape values that contain quotes, line breaks, or the selected separator. The sample keeps this logic in a dedicated CsvFormatter class.

```
private string EscapeValue(string value)
{
    if (!value.Contains('"') &&
        !value.Contains(_separator) &&
        !value.Contains('\r') &&
        !value.Contains('\n'))
    {
        return value;
    }

    return $"\"{value.Replace("\"", "\"\"", StringComparison.Ordinal)}\"";
}
```

The separator can be selected from the command line. The default is a comma, but semicolon, tab, pipe, space, or any single character can be used.

```
dotnet run
dotnet run -- --separator semicolon
dotnet run -- --separator "|"
```

This is helpful for regional spreadsheet workflows where semicolon-delimited CSV files are preferred.

### Running the Sample

Build the project:

```
dotnet build .\tx-table-to-csv.slnx
```

Run the console application from the project folder:

```
cd .\tx-table-to-csv
dotnet run
```

The sample HTML files are copied to the output directory during build. At runtime, the app reads them from the executable folder:

```
var sampleDirectory = Path.Combine(AppContext.BaseDirectory, "Samples");
var exportDirectory = Path.Combine(AppContext.BaseDirectory, "Exports");
```

CSV files are written to the Exports folder next to the executable.

Example output:

```
Using ',' as CSV separator.
Exported table 1 from customer-orders.html to customer-orders-table-1.csv.
Exported table 2 from customer-orders.html to customer-orders-table-2.csv.
Exported table 1 from nested-service-plan.html to nested-service-plan.csv.
  Warning: Skipped 1 nested table(s) as separate CSV export(s).
  Warning: Omitted nested-table content from 1 cell(s).
```

### Conclusion

TX Text Control provides access to a document's table structure through the server-side object model. By loading the document with ServerTextControl, iterating through Table, TableRow, and TableCell objects, and applying CSV escaping rules, document tables can be exported into a simple data exchange format.

The important design decision is to keep the CSV output focused on table data only. Surrounding document text, captions, and nested tables are document structure, not flat CSV data. Handling those cases explicitly makes the export predictable and easier to consume in downstream systems.

You can download the complete sample project from our GitHub repository below.

---

## About Bjoern Meyer

As CEO, Bjoern is the visionary behind our strategic direction and business development, bridging the gap between our customers and engineering teams. His deep passion for coding and web technologies drives the creation of innovative products. If you're at a tech conference, be sure to stop by our booth - you'll most likely meet Bjoern in person. With an advanced graduate degree (Dipl. Inf.) in Computer Science, specializing in AI, from the University of Bremen, Bjoern brings significant expertise to his role. In his spare time, Bjoern enjoys running, paragliding, mountain biking, and playing the piano.

- [LinkedIn](https://www.linkedin.com/in/bjoernmeyer/)
- [X](https://x.com/txbjoern)
- [GitHub](https://github.com/bjoerntx)

---

## Related Posts

- [Convert CSV to PDF in .NET C#](https://www.textcontrol.com/blog/2026/01/19/convert-csv-to-pdf-in-dotnet-csharp/llms.txt)
- [Why Table Control in Templates is Important for Professional PDF Creation in C#](https://www.textcontrol.com/blog/2025/04/04/why-table-control-in-templates-is-important-for-professional-pdf-creation/llms.txt)
- [Splitting Tables at Bookmark Positions and Cloning Table Headers](https://www.textcontrol.com/blog/2025/02/13/splitting-tables-at-bookmark-positions-and-cloning-table-headers/llms.txt)
- [Creating Advanced Tables in PDF and DOCX Documents with C#](https://www.textcontrol.com/blog/2024/09/30/creating-advanced-tables-in-pdf-and-docx-documents-with-csharp/llms.txt)
- [Inserting MergeBlocks with the DataSourceManager and Applying Table Styles in C#](https://www.textcontrol.com/blog/2024/04/09/inserting-mergeblocks-with-the-datasourcemanager-and-applying-table-styles-in-csharp/llms.txt)
- [Major SignFabric Updates: Stronger Audit Trails, Validation, and Recipient Workflows](https://www.textcontrol.com/blog/2026/06/17/major-signfabric-updates-stronger-audit-trails-validation-and-recipient-workflows/llms.txt)
- [Text Control Expands North American Conference Presence with WeAreDevelopers World Congress North America](https://www.textcontrol.com/blog/2026/06/12/text-control-expands-north-american-conference-presence-with-wearedevelopers-world-congress-north-america/llms.txt)
- [Converting HTML to Markdown in C# .NET](https://www.textcontrol.com/blog/2026/06/11/converting-html-to-markdown-in-csharp-dot-net/llms.txt)
- [Beyond WebSockets: A Glimpse into the Future of Document Editing with WebAssembly](https://www.textcontrol.com/blog/2026/06/10/beyond-websockets-glimpse-future-document-editing-webassembly/llms.txt)
- [Showcasing the Future of Document Processing at Developer World DWX 2026](https://www.textcontrol.com/blog/2026/06/08/showcasing-the-future-of-document-processing-at-dwx-developer-week-2026/llms.txt)
- [PDF Security Explained: Passwords, Permissions, Encryption and Digital Signatures in C# .NET](https://www.textcontrol.com/blog/2026/06/08/pdf-security-explained-passwords-permissions-encryption-and-digital-signatures-in-csharp-dotnet/llms.txt)
- [NDC Copenhagen 2026: Great Days in the Heart of Copenhagen's Developer Community](https://www.textcontrol.com/blog/2026/06/05/ndc-copenhagen-2026-great-days-in-the-heart-of-copenhagens-developer-community/llms.txt)
- [Automatically Mapping TX Text Control Form Fields to JSON Data in .NET C#](https://www.textcontrol.com/blog/2026/06/03/automatically-mapping-tx-text-control-form-fields-to-json-data-in-dotnet-csharp/llms.txt)
- [Getting Started with SignFabric: From Clone to Your First Signature Envelope](https://www.textcontrol.com/blog/2026/06/02/getting-started-with-signfabric-from-clone-to-your-first-signature-envelope/llms.txt)
- [We Never Pause - Join Us at NDC Copenhagen 2026](https://www.textcontrol.com/blog/2026/05/27/we-never-pause-join-us-at-ndc-copenhagen-2026/llms.txt)
- [MD DevDays 2026: Record Attendance, Packed Expo Hall, and Three Great Days in Magdeburg](https://www.textcontrol.com/blog/2026/05/21/md-devdays-2026-record-attendance-packed-expo-hall-and-three-great-days-in-magdeburg/llms.txt)
- [TX Text Control 34.0 SP4 is Now Available: What's New in the Latest Version](https://www.textcontrol.com/blog/2026/05/20/tx-text-control-34-0-sp4-is-now-available/llms.txt)
- [Techorama 2026: Welcome to The Document Forge](https://www.textcontrol.com/blog/2026/05/15/techorama-2026-welcome-to-the-document-forge/llms.txt)
- [Signed CycloneDX SBOMs for CRA Compliance Available for Text Control Products](https://www.textcontrol.com/blog/2026/05/08/signed-cyclonedx-sboms-for-cra-compliance-available-for-text-control-products/llms.txt)
- [Introducing SignFabric: An Open Source, Enterprise-Ready E-Sign Platform Built with TX Text Control](https://www.textcontrol.com/blog/2026/05/06/introducing-signfabric-an-open-source-enterprise-ready-esign-platform-built-with-tx-text-control/llms.txt)
- [TX Text Control vs IronPDF for Enterprise PDF Workflows: Complete Comparison Guide](https://www.textcontrol.com/blog/2026/04/28/tx-text-control-vs-ironpdf-for-enterprise-pdf-workflows-complete-comparison-guide/llms.txt)
- [Building a Modern Track Changes Review Workflow in ASP.NET Core C#](https://www.textcontrol.com/blog/2026/04/28/building-a-modern-track-changes-review-workflow-in-aspnet-core-csharp/llms.txt)
- [Document Classification Without AI: Deterministic, Explainable, and Built for Production in C# .NET](https://www.textcontrol.com/blog/2026/04/23/document-classification-without-ai-deterministic-explainable-built-for-production-in-csharp-dot-net/llms.txt)
- [Using QR Codes in PDF Documents in C# .NET](https://www.textcontrol.com/blog/2026/04/21/using-qr-codes-in-pdf-documents-in-csharp-dotnet/llms.txt)
- [Sanitizing Data in Document Pipelines: A Practical Approach with TX Text Control in C# .NET](https://www.textcontrol.com/blog/2026/04/20/sanitizing-data-in-document-pipelines-a-practical-approach-with-tx-text-control-in-csharp-dotnet/llms.txt)
