Skip to content
FormatKit

Free online XML to CSV converter

XML to CSV: you choose what a row is

This XML to CSV converter costs nothing, needs no sign-in, and works on documents up to 5 MB inside your browser. It starts by counting every element path in the file and asking which one is a row — because that single choice decides the whole table — then flattens each record so nested children become path columns like stock/units and attributes become @sku. Repeated children can be numbered, joined into one cell or reduced to the first, and every column that only some records supply is listed underneath the preview table.

  • 100% free
  • No signup
  • Up to 5 MB
  • Row element you pick
  • RFC 4180 quoting
Output delimiter
Line ending
Path separator
CSV

The delimited rows appear here.

Paste XML, open a file, or press Ctrl+V anywhere on this page.

Two records, one rectangle

These two <item> elements are both valid and carry different children — one has two tags and a nested stock block, the other has neither and adds a field of its own. A table has to hold both.

The source

<inventory>
  <item sku="ESP-01">
    <name>Espresso beans</name>
    <stock><units>420</units></stock>
    <tag>coffee</tag>
    <tag>fair-trade</tag>
  </item>
  <item sku="GRD-02">
    <name>Grinder</name>
    <discontinued>2026-05-01</discontinued>
  </item>
</inventory>

Rows from <inventory/item>

@sku,name,stock/units,tag[1],tag[2],discontinued
ESP-01,Espresso beans,420,coffee,fair-trade,
GRD-02,Grinder,,,,2026-05-01

joined instead of numbered

@sku,name,stock/units,tag,discontinued
ESP-01,Espresso beans,420,coffee; fair-trade,
GRD-02,Grinder,,,2026-05-01

Six columns for two records, four of them empty in one row or the other. Numbering the tags keeps them separately addressable and hard-codes a maximum of two; joining them keeps one stable column and makes a tag containing a semicolon ambiguous. Both readings are lossy, which is why the choice sits in the toolbar rather than in the source code.

How to convert XML to CSV

Three steps: load the document, choose the row element, decide how repeats and gaps are written.

  1. Load the document

    Send the document in however suits you: the editor, a file up to 5 MB, or a keyboard paste, which the page accepts wherever the cursor is. The moment it parses, every element path is counted and listed in the first dropdown — inventory/item, 340 occurrences, 12 fields — so the structure of the feed is on screen before you decide anything.

  2. Say which element is a row

    Pick the repeating element. Everything inside it becomes a column: a child element two levels down becomes stock/units, an attribute becomes @sku, and text sharing an element with children becomes #text. Change the path separator to a dot or an underscore if the consumer dislikes slashes in headers.

  3. Decide how repeats and gaps are handled, then export

    A record holding three <tag> children can become tag[1], tag[2], tag[3], one column with the values joined, or just the first with the rest dropped and counted. Fill the placeholder for cells no record supplied, choose comma, semicolon, tab or pipe with CRLF or LF endings, then read the table preview before Copy or Download.

Technical specifications

Row elementAny element path in the document, ranked by occurrence count and leaf-column count; the top 20 paths are offered
Column namingPath from the record element with /, . or _ as the separator; attributes marked @, text beside child elements as #text
Repeated childrenNumbered columns tag[1], tag[2]; one joined column with a separator you choose; or first-only with the discarded count reported. Numbering is decided across the whole file, not per record
Sparse recordsThe header is the union of all paths in first-seen order; missing cells take your placeholder and every sparse column is listed
Quoting and endingsRFC 4180: quotes added for the delimiter, ", CR, LF and edge spaces, inner quotes doubled; CRLF or LF; optional quote-every-field
DelimitersComma, semicolon, tab or pipe, independent of anything in the source document
Not carried overComments, processing instructions, namespace URIs, the DTD, element order between different names, and any structure deeper than the record you chose that repeats in a way one cell cannot hold
Speed, limits and cost20,000 records with 9 columns flatten in 0.10 s once the document is parsed, and ranking every path in a 4.5 MB file takes 0.15 s. 5 MB per document, 500 levels of nesting, first 12 rows shown in the preview table; free, no signup, flattened in this browser tab

Frequently asked questions

Which element should become a row?

The one that repeats at the level you care about — usually the child of the root, like <item> inside <inventory> or <entry> inside <feed>. The dropdown ranks every path in your document by how often it occurs and shows how many leaf columns it would produce, so the choice is a fact about your file rather than a guess. Choosing an element that occurs once gives a single very wide row, which is a useful signal that you picked a container rather than a record.

How do nested child elements become columns?

By their path from the record element, joined with a separator: <stock><units>420</units></stock> inside a record becomes a column named stock/units. Depth is not limited, so a three-level structure produces headers like shipping/address/postcode, and attributes hang off the same path with an @ — price/@currency. This keeps distinct values in distinct columns, which is the point of flattening; a converter that emits stock as one blob has not flattened anything.

One product carries three tags and the next carries one. Now what?

You choose between three answers, and the numbering is decided across the whole file rather than per record. Numbered columns give tag[1] and tag[2]; joining puts every value in one cell separated by a string you pick; keeping the first discards the rest and counts what it dropped. The document-wide rule matters: if one record has two tags and the next has one, the single tag still lands in tag[1] rather than in a column called tag, so the column keeps meaning the same thing all the way down.

What if some records have children that others do not?

The header is the union of every path seen, in the order they first appear, and records missing a path get the placeholder. XML has no obligation to make sibling elements identical — an optional <discontinued> appears on two products out of 300 — while a table has to be rectangular, so the columns are as wide as the widest record. The report names every sparse column, which is the quickest way to spot an optional field you did not know the feed had.

Do attributes end up in the CSV?

Yes, as columns marked with @, and you can switch them off in one click. Attributes usually carry the identifiers — sku, id, currency, status — so dropping them is the fastest way to lose the key you would join on later. They are flattened by the same path rule as elements, so an attribute on a nested child becomes price/@currency rather than colliding with a top-level one.

When does a field get quoted, and why CRLF?

A field is quoted when it contains the delimiter, a double quote, a CR, an LF, or a leading or trailing space, and any quote inside it is doubled — that is RFC 4180 section 2, and it is why a product description with a comma does not shift every column to its right. CRLF is the line ending the same memo specifies and what Excel expects on Windows; LF is the option for anything Unix-shaped downstream. Long descriptions with real line breaks inside them stay one record, quoted.

My file has several different record types — can I get one CSV?

Not as one table, and no converter should pretend otherwise. A document holding <customer> and <invoice> elements describes two entities with different columns, and forcing them into one sheet gives you a header with every field of both and half the cells empty. Convert once per record type — change the dropdown, export again — which is the same thing you would do with two database tables.

About flattening a tree into rows

XML is a tree of arbitrary depth where siblings need not match, and CSV is a rectangle where every row has the same cells in the same order. There is no general mapping between those two shapes, only a projection you have to choose, and the choice is the record element. Pick <item> and you get a product catalogue; pick its parent and you get one enormous row; pick a grandchild and you get a table of stock levels with no product names attached. Nothing in the document marks which is right — a schema might, through cardinality, but a well-formed file on its own does not — so this page counts the occurrences of every path and lets you decide with the numbers in front of you.

What makes the projection lossy is repetition below the row. A record with two <tag> children is a one-to-many relationship, and first normal form says a cell holds one value, so a single table cannot represent it honestly. Numbering the columns fixes the arity at whatever the widest record happens to have, which breaks the day a record arrives with one more. Joining the values into a cell keeps the column count stable and pushes the problem onto whoever has to split the string again — and onto any value that contains the separator. Taking the first is honest about discarding data and tells you how much. A relational answer would be two exports, the records and their tags, joined on a key; if that is where this is heading, keep the attribute columns, because the identifiers usually live there.

Once the rows exist, the rest is quoting, and RFC 4180 is short enough to be worth reading: quote a field that contains the delimiter, a quote, a CR or an LF; double any quote inside; end records with CRLF. Descriptions with commas and multi-line addresses are handled by that rule and by nothing else, which is why output from here is safe to open in Excel or feed to a loader that follows the memo. If you would rather keep the hierarchy than flatten it, XML to JSON preserves nesting instead of projecting it away, and the CSV viewer will open the export you just made if you want to sort it before sending it on.

Your feed stays on this machine

Your document is parsed and flattened by JavaScript inside this tab; no part of it is uploaded or stored, and the CSV you download is assembled locally. A supplier feed or an export with real order data can be turned into a spreadsheet here without a copy existing anywhere else.