Why XML ends up needing to be CSV
XML is still the export format of a great many systems: accounting and billing software, government portals, product feeds for shops, RSS and Atom news feeds, map files in KML, sitemaps, and older business applications of every kind. It carries the data faithfully, but it is a tree of nested tags, and nobody can sort, filter or total a tree. A spreadsheet needs rows and columns.
In almost every XML export, the useful part is a list: many product elements inside a products element, many invoice elements inside an invoices element, many item elements inside a channel. This converter finds that list and lays it out as a table, one record per row.
How the rows are found
The tool walks the whole document and counts which element repeats most often under the same parent. That is nearly always the record you want, and it is chosen automatically. The row element list then shows the other repeating elements with their paths and how many times each appears, so if the automatic choice is wrong, for example because each record has many repeated line items inside it, you can pick the right element and convert again.
For each row element, every child element becomes a column named by its path, such as price or author.name, and every attribute becomes a column prefixed with @, such as @id or @currency. Records that do not have a particular child simply leave that cell blank, so all rows line up even when the XML is not perfectly regular.
Repeated children inside a record
Sometimes one record contains a list of its own, for example a book with several author elements. The "Repeated children" option decides how those are written. Numbered columns gives author, author_2, author_3 and so on, which keeps every value in its own cell. Join into one cell puts all the values in one cell separated by a semicolon, which is tidier when the list is short and you mainly want to read it.
What is kept as written
Text is taken exactly as it appears in the XML, with entities such as & turned back into the characters they stand for and CDATA sections read as plain text. Namespace prefixes, such as g:price in a Google shopping feed, are kept in the column names rather than guessed away, so two different fields with the same local name never collide.
Mixed content, where text and tags are interleaved inside one element as in a paragraph of formatted text, is kept as the combined text of that element. XML comments and processing instructions are ignored.
Opening the result in Excel
Values containing commas, quotes or line breaks are quoted correctly, so they stay in one cell. Choose semicolon as the delimiter if your Excel uses a comma for decimals, and tick the byte-order mark if the data has accented letters or text in non-Latin scripts; this makes Excel read the file as UTF-8 and show those characters properly.
When the XML will not convert
XML is strict. A missing closing tag, an unescaped ampersand in text, or a file that was cut off part way makes the whole document invalid, and the page will say that the XML could not be read. Open the file in a text editor and look near the end, or where the error points, for the broken tag. HTML pages are not XML and will usually be refused.
Very large files take a little longer because the whole tree is held in memory, but ordinary exports of a few megabytes convert in a moment.
A small worked example
Take a catalogue file with a catalog element holding fifty book elements. Each book has an id attribute, a title, a price with a currency attribute and one or more author elements. The converter picks book as the row element, because it repeats fifty times, and produces fifty rows with the columns @id, title, price, price.@currency and author. A book with two authors gets a second column, author_2, or both names in one cell if you choose to join them. If you had wanted one row per author instead, you would simply pick the author entry in the row element list and convert again.
Privacy
The XML is parsed by your browser in this tab. It is never uploaded, no account is needed, and closing the tab clears it.