Pular para o conteúdo principal

XML to CSV

This converter flattens XML into RFC 4180 CSV in your browser. The root element's repeating children become rows, their attributes become @-prefixed columns, and element text lands in named columns with CRLF endings and quoting only where the grammar demands it. Nothing is uploaded.

Só local

A interface desta ferramenta está em inglês.

O guia abaixo está disponível apenas em inglês.

XML to CSV explained

Most real XML that behaves like a table shares one shape: a container element holding many same-named children, each child standing for one record — a catalogue of books, a log of entries, a list of orders. This converter looks for exactly that shape. Find the root's repeating child and the rest is mechanical: each child becomes a row, its attributes and inner elements become columns, and the union of every column across every row becomes the header, in the order they were first seen.

The conventions are the ones every XML bridge uses, and they are made explicit here: an attribute keeps its name but gains an @ prefix, so id="bk101" becomes the @id column; an element's text becomes its #text value; and a child element that repeats inside one record explodes into indexed columns rather than being silently merged. The CSV side is strict RFC 4180 — CRLF row endings, double-quote escaping only where a field contains a comma, quote or newline — and values cross over verbatim, with no numeric coercion to reformat a postal code.

Everything runs in this browser tab. The XML is parsed by an in-page engine and the CSV is built from the parsed tree; neither touches a network — open DevTools, watch the Network panel stay silent, and the claim checks itself.

Building the XML from a spreadsheet export instead? The CSV to XML converter applies these same conventions in the other direction.

What the CSV side guarantees — quoting, CRLF, doubled quotes — is written up properly in the RFC 4180 guide on this site.

How the conversion actually works

The document is tokenised once into a tree, then the tabular read is a separate, honest step: the tree either has the repeating-children shape or it does not, and pretending otherwise would produce a CSV that looks fine and means something else. When the shape is found, every record is flattened to leaf paths, and the header row is the ordered union of those paths across all records — first-seen first, so column order is stable and predictable rather than alphabetical by accident.

  • Parse: a single-pass tokenizer builds the element tree; comments, DOCTYPE and processing instructions are skipped, and a second root element is rejected with a line number.
  • Select: the root's first repeating child element provides the rows — <catalog> full of <book> children is the classic case.
  • Flatten: attributes become @columns, element text becomes #text, and deeper nesting becomes dotted paths such as author.#text.
  • Emit: one CRLF-terminated row per record, fields quoted only when a comma, quote or newline forces it.

How XML features map to columns

XML has three ways to carry a value — attributes, text content and child elements — and a flat grid has one: a named column. The mapping below is the standard one, chosen so that no two features of the source can collide in the output and so the header itself tells you which kind of value each column came from.

XML constructColumnExample cell
attribute id="bk101"@idbk101
element text <price>5.95</price>price.#text5.95
element with attributes and text@sku plus #textA-1, Widget
repeated grandchildrenbook[0].#text, book[1].#textone, two

Values cross over verbatim

There is no type-inference step between the XML tree and the CSV, deliberately. XML text is text, so 44.95 arrives as the characters 44.95, a postal code keeps its leading zero, and a value like 1e5 is not expanded into 100000. Entities are carried through the same way: the parser is not a validating parser and does not rewrite entity references, so what lands in a cell is exactly what the source text contained. If the destination needs typed values, pair this tool with the CSV to SQL converter, which infers types from the cells at that point, where the choice is visible and reversible.

  • Numbers keep their exact characters — no precision is invented or lost.
  • Whitespace inside a text node is preserved; whitespace between elements never becomes data.
  • Empty elements (<debug/>) produce a column with an empty cell rather than disappearing.

Where this converter refuses to guess

Two structures would force the converter to invent information, and both are refused with a specific message instead. The first is a document with no repeating child element — a single root containing nothing tabulable cannot become rows without inventing a row shape. The second is a document with more than one root element, which is not one document at all; the error names the offending second element and its line, and nothing is written. A fragment that almost fits is still a fragment, and the fastest fix is to delete or rename the wrapper element before pasting.

  • No repeating children: error naming the expected <root><item>…</item></root> shape.
  • Multiple roots: rejected, with the second element and its line reported.
  • Mismatched closing tags: rejected at the point the tree stops being well-formed.

Frequently asked questions

Does converting XML to CSV upload my file anywhere?

No. The XML parse and the CSV build both happen inside this browser tab with JavaScript that was loaded once when the page opened. There is no API route to send data to, and the page's Content-Security-Policy sets connect-src 'self', so the browser itself would block any outbound request. Both claims are checkable in DevTools: watch the Network panel while you convert — no request appears.

Which XML elements become the CSV rows?

The converter looks at the root element's children and takes the repeated one — the same-named element appearing many times, such as <book> inside <catalog>. Each occurrence becomes one row. If no child repeats, each object-shaped child is treated as its own record instead, and a root with nothing tabulable inside is refused with a named error rather than being flattened into a misleading one-row file.

Why do some column names start with @ or contain #text?

The prefixes record where each value lived in the XML. An @ prefix marks an attribute — id="bk101" becomes the @id column — and #text marks an element's own text, which needs a name of its own when the element also has attributes or children. The prefixes prevent collisions: an element named id and an attribute named id would otherwise fight over one column, and the header would not tell you which was which.

Are numbers converted, or do values stay as written?

Values stay exactly as written. The tree keeps text as strings and the CSV writer does no type inference, so 44.95 crosses as 44.95, a postal code like 02134 keeps its leading zero, and nothing is reformatted behind your back. This is the same policy the site's XML to YAML converter follows, so a file converted either way shows the same values character for character.

How are quoted fields and line breaks handled in the output?

Per RFC 4180: a field containing a comma, a double quote or a newline is wrapped in double quotes, and a quote inside such a field is doubled. Rows end with CRLF, the terminator the specification defines and the one spreadsheet software expects. Fields are quoted only when the grammar forces it — no decorative quoting — which keeps the file smaller and easier to diff than a quote-everything export.

What happens to XML comments and the DOCTYPE line?

They are skipped. Comments, the DOCTYPE declaration and processing instructions carry no tabular data, so the tree simply never includes them; parsing continues from the element structure. The one thing the converter insists on is a single root element — a document with a second top-level element is rejected with the element's name and line number, because two roots are two documents, not one row set.