Skip to content
datahacks.dev
XML

XML Versus CSV for Exchanging Tabular Data Between Systems

A partner asks for XML for a flat table. Measured on 100,000 rows, XML was 2.7 times the CSV size, though gzip nearly erased the gap. When each is right.

6 min read
Summarize in AI
Flat illustration of two options weighed side by side, with the XML logo.

The request arrives as a polite sentence: "can you send us the data as XML?". The data is a flat table with a few columns and a lot of rows. You can do it, and the question to ask is whether you should. Sometimes the answer is yes, for reasons that have nothing to do with the table. Often the honest answer is that the receiver has a pipeline built for XML and would be better served by CSV, if someone offered it. This post gives you the numbers and the questions for that conversation.

The same table, two ways

CSV:

Text
id,customer,amount,day
1,customer-42,19.90,2026-03-14
2,customer-7,254.10,2026-11-02

XML, the way most exporters write a table:

XML
<rows>
  <row><id>1</id><customer>customer-42</customer><amount>19.90</amount><day>2026-03-14</day></row>
  <row><id>2</id><customer>customer-7</customer><amount>254.10</amount><day>2026-11-02</day></row>
</rows>

Every value in the XML carries its column name twice, once to open and once to close, and every row carries the row wrapper. That is the price of a self-describing format applied to data that is already described by a header.

Measured on 100,000 rows:

Text
CSV 3756283 gzip 1040653
XML 10156272 gzip 1196619 ratio 2.70

Uncompressed, the XML is 2.7 times the CSV. Compressed with gzip, it is 1.20 MB against 1.04 MB, a 15 percent difference. The reason is the repetition that makes XML large also makes it compress: <customer> and </customer> appear 100,000 times, and a compressor turns each into a few bits. So the size argument for CSV depends on whether the file travels or sits compressed. On a network with compression on, or in an archive, the gap nearly vanishes. In memory, on disk uncompressed, and in a parser, it does not.

The costs that do not compress away

Parsing time and memory. A CSV reader is a loop over lines. An XML parser builds names, attributes and nodes for every cell. The 10 MB file loaded as a tree needs about ten to fifteen times its size in memory (how much memory a DOM parser needs), while the CSV loads in a stream with constant memory.

Bulk loaders. PostgreSQL's COPY, MySQL's LOAD DATA, SQLite's .import and DuckDB's read_csv read CSV natively and fast. XML needs a parser in between, as in streaming XML into PostgreSQL without a DOM, and a mapping from elements to columns that someone must write and maintain.

Spreadsheets. CSV opens in Excel and Sheets with a double click. XML needs an import map, and it often comes out wrong (opening XML files in Excel without mangled data).

Eyes. A person can scan a CSV. A person reads about a quarter as many rows of XML per screen.

What XML gives you that CSV cannot

None of the above matters if the table is not really flat. These are the cases where XML is the right answer:

Nesting. An order with a variable number of lines is not a table. Flattening it into CSV repeats the order columns on every line, or needs two files and a key. XML holds it naturally.

Optional parts. A row where some columns do not apply is awkward in CSV, which has only empty cells, and clear in XML, where the element is absent.

Types and units. CSV has no types: 007, 1e5, 2026-03-14 and N/A are all just text (why a CSV file has no types). With a schema, XML says which element is an integer, a date or a decimal and rejects a row that disagrees.

Validation. An XSD lets the sender run a check before sending and the receiver before loading. A CSV can be validated too, but with weaker tools and conventions.

Metadata. Units, currencies, source and export time can travel in attributes and a header element. In CSV they are in a separate document or in a naming convention that someone must remember.

A receiver that requires it. If the partner's system accepts XML only, no argument about size will change that. Deliver good XML.

Giving XML anyway: do it well

If you must send XML for a flat table, spend a little effort on it:

  • Use attributes for short values to cut size and clutter: <row id="1" customer="customer-42" amount="19.90" day="2026-03-14"/> is about a quarter shorter than the element form for this row. Remember that attributes normalize whitespace, so keep long text in elements (when attributes are the better choice).

  • Publish a schema so the receiver knows the types, and validate your own output against it.

  • Compress in transit and say so.

  • Keep names short but meaningful, and stable.

  • Offer CSV as well. Many partners accept both once someone mentions it.

Handling the conversation with the receiver

When a partner asks for XML, find out why before you answer. The reason is usually one of four: their import tool only reads XML, their policy requires a schema-validated format, they assume XML is the safe default, or they had a bad experience with CSV and its quoting. Each has a different answer. A tool limit means you deliver XML and make it good. A policy means you publish the schema and validate against it. An assumption is a chance to offer both and let them compare, and a bad CSV experience usually points to an encoding or delimiter problem that a specification fixes: UTF-8, comma, double-quote escaping, a header row, ISO dates.

Write whichever you agree on into a short interface document. One page covering the file name pattern, encoding, column or element list with types, how nulls appear, and what happens to a file that fails validation prevents more support tickets than any choice of format.

The cluster hub is choosing XML over the alternatives, or not. Going the other way, see converting XML to CSV for spreadsheet users and converting CSV to XML with a template. For the CSV side of the story, read everything a CSV file does and does not promise you. The CSV format is described in RFC 4180, and gzip in RFC 1952. Flatten a snippet quickly with the XML to JSON tool.

When CSV is the wrong answer for tabular data

The table has embedded structure. Multi-line text, nested lists and optional groups turn CSV into a quoting problem. If the receiver will parse your quoting rules incorrectly, use a format that does not need them.

Types matter downstream. Leading zeros in identifiers and long numbers lose their meaning in a spreadsheet. If your IDs are 00123, either use a typed format or quote them and document the column as text.

Several tables travel together. A parent file and a child file joined by a key can drift apart. XML, JSON or a database dump keeps them in one document.

Encoding is a recurring problem. CSV does not carry its encoding, and XML does in its declaration. For text in many scripts, a format that declares UTF-8 saves a support thread per partner.

Also inCSV
Share

Keep reading

Get new articles by email

We send one email when a new article is published. No spam.

Unsubscribe in one click. No spam, ever.