Preserve XML Structure When You Publish CSV Tables
Learn when XML fits better than CSV, how to split nested records into related tables, and which validation checks prevent broken public datasets online.

XML and CSV can hold many of the same scalar values, but CSV cannot directly preserve XML’s hierarchy. To publish XML as a sortable table, choose one repeating XML element as the row, map its single-value fields to columns, and move repeated child elements into related CSV tables rather than duplicating the parent row.
Describe the XML structure; the planner shows whether you need one CSV, related tables or the original XML.
XML-to-CSV Structure Planner
Choose the shape and preservation requirements of the source.
Use one main row per repeating record and one child-table row per repeated value. Connect them with a primary key and foreign key.
Basis: W3C Model for Tabular Data and Python ElementTree documentation. Row counts are — until the source XML is inspected.
XML and CSV Represent Different Data Shapes
XML organizes content as a hierarchy of elements and attributes. CSV organizes values into rows and columns. Conversion is therefore a data-modeling task, not a file-extension change.
| Question | XML | CSV |
|---|---|---|
| Natural structure | Nested tree | Rectangular table |
| Field names | Elements and attributes | Usually one header row |
| Repeated values | Child elements | Extra rows or tables |
| Types and constraints | Can use a schema | Usually documented separately |
Python’s ElementTree documentation describes XML as inherently hierarchical and represents it as a tree (Python ElementTree documentation). The W3C tabular-data model describes rows as having the same number of cells, with each column holding the same property across rows (W3C Model for Tabular Data).
CSV is suitable for publication only after the relevant source data can be expressed honestly in that rectangular shape. If order, mixed text and elements, namespaces, comments or schema constraints are material, retain the XML alongside any CSV derivative.
Choose the Repeating Element That Becomes a Row
Start by locating the XML element that represents one observation. It might be a record, transaction, permit, product or measurement. Each occurrence of that element should normally produce one row in the main CSV.
Consider a sample dataset containing two record elements. Each record has an id attribute, a title, date and amount. The amount has a currency attribute. A nested tags element can contain several tag children.
The first record contains these values:
| Field | Value |
|---|---|
id |
A001 |
title |
North Bridge repair |
date |
2026-09-15 |
amount |
1250.00 |
currency |
USD |
tags |
transport; capital |
The second record has ID A002, the title Library equipment, the date 2026-09-18, an amount of 875.50 USD and the tag education.
The single-value fields map naturally to columns in records.csv. Displayed vertically to keep the table readable on phones, its two data rows contain:
| Field | A001 | A002 |
|---|---|---|
id |
A001 | A002 |
title |
North Bridge repair | Library equipment |
date |
2026-09-15 | 2026-09-18 |
amount |
1250.00 | 875.50 |
currency |
USD | USD |
Attributes do not need a special CSV representation. The record’s id attribute becomes an id column, while the amount’s currency attribute becomes a currency column. Document that mapping so users can trace each output field to its XML source.
Put Repeated Children in Related CSV Tables
Do not create two copies of record A001 merely because it has two tags. Duplicating the parent row would inflate the apparent number of projects and could corrupt counts and amount totals.
Instead, create record_tags.csv with one row for each relationship:
record_id |
tag |
|---|---|
| A001 | transport |
| A001 | capital |
| A002 | education |
Here, records.id is the primary key and record_tags.record_id is a foreign key. This preserves the one-to-many relationship without hiding several values in one cell. Apply the same pattern to nested payments, locations, participants or other repeated groups; see linking related CSV tables.
A delimited list such as transport; capital may be acceptable for display when the tags will never be filtered, counted or joined. It is a weaker interchange format because readers must know the separator and escaping rules. A related table is safer when each child value matters independently.
Make the Converter Match the Known XML Structure
A trustworthy converter states which element becomes a row and which paths become columns. For the sample structure, an ElementTree-based Python conversion would:
- Parse
data.xmland select eachrecorddirectly under the root. - Read the record’s
idattribute and the text oftitleanddate. - Read the amount text and its
currencyattribute. - Write one row to
records.csvfor each record. - Write one row to
record_tags.csvfor each nestedtags/tagelement.
Python’s csv.DictWriter handles delimiters and quoting, so rows should not be assembled through string concatenation. RFC 4180 describes the common convention: fields containing commas, double quotes or line breaks are enclosed in double quotes, and each quote inside a quoted field is doubled (RFC 4180).
Python’s CSV documentation recommends opening files with newline=''. It also notes that CSV readers normally return strings instead of assigning data types automatically (Python csv documentation). Dates, decimals, identifiers and currencies therefore need explicit validation rather than relying on inferred spreadsheet types.
Adapt the conversion when records occur at another path, meaningful whitespace must be preserved, or values appear in different attributes or elements. Additional nested groups may require additional related tables.
XML namespaces also change selectors. ElementTree expands namespaced tags to a {URI}name form, so use expanded names or a namespace map. The same ElementTree documentation covers namespace selection and provides iterparse() for incremental processing of large XML files. Processed elements can be cleared to reduce memory use.
Validate Counts, Keys and Values Against the XML
A CSV opening successfully does not prove that the conversion preserved the data. Compare the generated files with the XML source.
- Record count:
records.csvshould contain one data row for every selected XMLrecord. - Primary key:
idshould be present and unique if it identifies a record. - Foreign keys: every
record_tags.record_idshould match an ID inrecords.csv. - Cardinality: the number of XML
tagelements should equal the number of rows inrecord_tags.csv. - Missingness: determine whether a missing element, an empty element and a numeric zero have different meanings.
- Types: validate date syntax, decimal syntax, units and currency instead of accepting spreadsheet guesses.
- Text: inspect commas, quotation marks, line breaks and non-ASCII characters in the parsed output. Use the UTF-8 CSV checklist and CSV quoting rules where needed.
Keep the original XML, conversion logic, field mapping and validation results together. CSV alone does not retain XML element order, comments, namespaces, the distinction between attributes and child elements, or schema constraints unless those details are preserved separately.
Use the example process only with XML you trust. Python warns that attacker-controlled XML can abuse parser features for denial-of-service attacks and that safety depends in part on the Expat version used by the runtime (Python XML security guidance). Applications accepting untrusted XML need parser limits and security controls designed for that threat model.
Publish the Validated Output Tables
As of September 29, 2026, TablePage accepts CSV, TSV, XLSX and XLS uploads, but not XML, and creates a public dataset page with a filterable table (TablePage). Upload the validated records.csv as the main dataset. If tags matter for filtering or analysis, publish record_tags.csv separately and describe the record_id relationship on both pages.
Remove confidential, personal or otherwise sensitive fields before upload. Include the source, retrieval date, conversion method, field definitions and update schedule so readers understand that the tables are modeled derivatives rather than lossless copies of the XML.