XML to CSV
Most XML to CSV converters ask you to upload a file and then decide for you which element is a record. This one shows both decisions and lets you change either. Paste the XML and the tool reads it as characters, picks the element that repeats, and lists the column paths those records actually carry: for a file of orders that is the row path /orders/order and the columns @id, name and qty. Type a different path and the table follows. A child that is missing from one record becomes an empty field so the columns never shift, values carrying a comma, a quote or a line break are quoted the way RFC 4180 describes, and everything the reader saw but did not export is listed underneath as a warning. The DOCTYPE is refused rather than obeyed, so a pasted export cannot point this page at a file or a URL.
Rows detected at /orders/order, columns detected from the records. When one column path matches several nodes in a row, they are joined with "; ".
- The column "qty" is missing from 1 of the 2 rows, so those fields are empty and the columns stay aligned.
2 rows from /orders/order, 3 columns, 1 warnings, 0 network requests made.
- id,name,qty 1,"Wrench, 8mm",2
- id,name,qty 1,"Wrench, 8mm",2 2,Hammer,The column "qty" is missing from 1 of the 2 rows, so those fields are empty and the columns stay aligned.
- The DOCTYPE points at an external DTD (http://example.com/orders.dtd). DTD processing is off here, so the file is refused rather than resolved, and nothing at that address is read or fetched. Delete the DOCTYPE and convert the elements.
Up to 4 MB of XML in one pass, read here in your browser with nothing uploaded and no account. Leave both boxes empty and the tool picks the element that repeats and the columns those records carry; type a path to overrule it. A column path is a child name, an attribute like @id, a nested path like address/city, or a dot for the text of the row element itself, and a namespace prefix never has to be typed. Up to 256 columns, elements nested up to 400 deep, and the panel prints the first 40 rows while the CSV you copy or download holds every one. Your three choices and your draft are kept in this browser alone, drafts up to 200,000 characters, and the Start over button above the tool forgets both.
Common questions
- How does the tool decide which element becomes a row?
- It counts the element paths in the file and takes the one that repeats most, breaking a tie in favour of the shallower path. For a file of orders that is /orders/order, and the paths it considered sit under the box as buttons, up to four of them. Type your own path to overrule it: an absolute path such as /orders/order, or just the element name, which matches that name anywhere in the tree. A namespace prefix never has to be typed, so /orders/order also selects ns:order.
- What happens when one record is missing a field?
- The field is written empty and the columns stay where they are. In the sample, the second order has no qty, so its line is 2,Hammer, with a trailing empty field rather than a row that is one column short. The tool also says so: a warning names the column and how many of the rows it was missing from, because a converter that silently shortens a row is the reason CSV imports go wrong two steps later.
- Is it safe to paste XML that came from somewhere else?
- That is what this converter is built around. The XML is read as characters and turned into plain objects, so nothing in it is constructed, evaluated or resolved. DTD processing is off: a DOCTYPE that declares an entity, or that names an external DTD, stops the conversion with a message naming it, and nothing at that address is read or fetched. That single rule is also what bounds an entity bomb, because a declaration is never expanded. Elements nested more than 400 deep are refused rather than read part way, and nothing is uploaded.
- How are commas and quotes inside a value handled?
- By RFC 4180. A field carrying a comma, a double quote or a line break is wrapped in double quotes, and a double quote inside such a field is doubled. A product called Wrench, 8mm comes out as the quoted field "Wrench, 8mm", so the comma stays inside the value instead of splitting the row. Records are separated by a carriage return and a line feed, which is the line ending the same document specifies.
- What if one column path matches several nodes in the same row?
- You choose. By default the values are joined into one field, separated by a semicolon and a space, so two tags come out as red; blue, and a warning says how many rows that happened in. The other two settings keep only the first match, or write the number of matches instead, which is useful when you want a count of line items rather than their contents. Whichever you pick, the row keeps exactly one field per column.
- How large a file can it take, and is anything uploaded?
- Up to 4 MB of XML in one pass, and nothing is uploaded: the conversion happens in this tab and makes no network requests. Larger than that and the paste is refused with both sizes quoted rather than quietly cut down, so split the export and convert it in parts. The panel prints the first 40 rows while the CSV you copy or download holds every one. Your three choices and a draft of up to 200,000 characters stay in this browser, and the Start over button above the tool forgets them.
The XML is parsed inert with DTD processing and entity expansion switched off, so an external entity is refused rather than resolved and no file or URL it names is fetched. Rows come from the element path you select and each column from its own path: a missing child becomes an empty field so the columns never shift, and values are quoted by RFC 4180. Nodes that match nothing are listed as warnings.