Skip to content
Your data never leaves your browser

XML to CSV Converter

Hierarchical data, flattened. For spreadsheet people.

Input
Output

What this does

DEVS: DOMParser (application/xml). Row tag = most frequent direct child of the root. Columns = row attributes as @name, then direct child elements, cell value = textContent. Papa.unparse with CRLF line endings.

Paste XML where one element repeats, like a list of <book> or <url> entries, and get one CSV row per entry. The tool looks at the outermost element's direct children and picks the tag that shows up most. Each of those becomes a row.

Columns come from two places. Attributes on the row element become columns with an @ in front, like @id. Child elements become columns named after their tag. A row that's missing one gets an empty cell.

A small catalog goes in:

<?xml version="1.0" encoding="UTF-8"?>
<catalog>
  <book id="bk101" lang="en">
    <title>XML Developer's Guide</title>
    <author>Gambardella, Matthew</author>
    <price currency="USD">44.95</price>
  </book>
  <book id="bk102">
    <title>Midnight Rain</title>
    <price currency="USD">5.95</price>
  </book>
</catalog>

And comes out as:

@id,@lang,title,author,price
bk101,en,XML Developer's Guide,"Gambardella, Matthew",44.95
bk102,,Midnight Rain,,5.95

The second book has no lang or author, so those cells are empty. The currency attribute on price is gone, because only the row element's own attributes make it into the CSV.

Common use cases

Auditing a sitemap. Paste sitemap.xml and you get a loc and lastmod column per URL, ready to sort.

Product feeds and exports from older systems. Namespaced tags keep their prefix, so a Google Shopping feed's g:id becomes a g:id column (after the RSS trim below).

Getting any list-shaped XML into a spreadsheet, where you can finally sort and filter it.

Things to know

Rows are only looked for one level under the root. If your list sits deeper, the tool grabs the wrong level. RSS is the classic case: everything lives inside <rss><channel>, so you get a single row. Delete the <rss> wrapper so <channel> is outermost, and each <item> becomes a row. If the feed uses prefixes like g:, move the matching xmlns:g="..." attribute onto <channel> first, or the parser rejects the unbound prefix. SOAP envelopes need the same trim.

Siblings that aren't the row tag, like a feed's own title, are skipped. If two tags tie for most common, the first one wins.

Nested elements don't get their own columns. Their text runs together in one cell, so a <customer> holding a name and an email comes out as Adaada@example.com, plus any indentation if the XML is pretty-printed. If a row repeats a child, like two <tag> elements, only the first is kept. For deep structures, XML to JSON is the better fit.

Values come through as text, untouched: 02134 and 1.50 stay exactly that. Entities get decoded and CDATA becomes plain text. A list of bare text elements, like a run of <name> tags, has nothing to turn into columns and stops with an error.

Privacy

Parsing uses your browser's built-in XML parser. The file you paste never gets uploaded, because there's nowhere for it to go.

Questions

How do I convert an XML file to CSV for Excel?

Open the file in a text editor, copy it all, paste it here, and click Convert. Download saves output.csv. If accented letters look wrong in Excel, import it with Data > From Text/CSV and pick UTF-8.

Why do I get one row with only my first record in it?

Your repeating elements aren't direct children of the outermost element, so the wrapper became the single row and only the first record made it into its cells. Trim the outer layers until the records sit right under the root, then convert again.

What happens to XML attributes?

Attributes on each row element become columns named with an @, like @id or @lang. They come first, before the child-element columns. Attributes on anything deeper are dropped.

Why does &nbsp; break the conversion?

XML only knows five named entities: &amp;, &lt;, &gt;, &quot;, and &apos;. HTML ones like &nbsp; or &eacute; aren't defined, so the parser stops. Swap them for numeric references (&#160; is a non-breaking space) or the plain character.

Why does it complain about the XML declaration?

The <?xml ...?> line has to be the very first thing in the document. A blank line or a space above it is a parse error. Delete whatever sits before it.