XML to Excel Converter
Drop an XML file and take back an .xlsx workbook. Nested elements become dotted columns rather than one unreadable cell, attributes arrive as columns of their own, and padded codes keep their zeros. It all happens in this tab.
Want to drop columns or filter records first? Open the app
The XML that ends up needing a spreadsheet
Nobody converts XML for the pleasure of it. It happens because a system that only speaks XML has handed over something a person now has to sort, filter, or forward. Five kinds of file account for almost all of it:
- Vendor and marketplace feeds. Product catalogues from a wholesaler or a shopping channel arrive with attributes on every item and a shipping block underneath. Merchandising wants columns.
- Finance and payroll exports. Bank statements in ISO 20022, older payroll dumps, tax filings. Reconciliation happens in a workbook, never in a tree view.
- Saved SOAP responses. Line forty captured responses up next to each other and you can finally see which optional fields the vendor populates and which are always empty.
- Published reference data. Regulatory filings, transport timetables, survey extracts. XML is what the publisher ships; Excel is where the questions get answered.
- Configuration under review. Two hundred entries in a build file or a resource bundle become two hundred rows, and the duplicates and gaps stop hiding.
The hard part is never the conversion. It is what happens to the nesting, which is what most of this page is about.
Worked example: an order export with a customer block
Each order here carries two attributes, a nested customer, and a total that has an attribute and a value at the same time. The third order has a field the first two lack.
<orders>
<order id="A-1041" channel="web">
<placed>2026-02-03</placed>
<customer>
<name>Priya Menon</name>
<city>Pune</city>
</customer>
<units>3</units>
<total currency="INR">4820.00</total>
</order>
<order id="A-1042" channel="phone">
<placed>2026-02-03</placed>
<customer>
<name>Daniel Roth</name>
<city>Leipzig</city>
</customer>
<units>1</units>
<total currency="EUR">96.50</total>
</order>
<order id="A-1043" channel="web">
<placed>2026-02-04</placed>
<customer>
<name>Sofia Duarte</name>
<city>Porto</city>
<postcode>04002</postcode>
</customer>
<units>12</units>
<total currency="EUR">31.00</total>
</order>
</orders>
Paste it into the box above and the workbook holds nine columns:
| id | channel | placed | customer.name | customer.city | units | total.currency | total | customer.postcode |
|---|---|---|---|---|---|---|---|---|
| A-1041 | web | 2026-02-03 | Priya Menon | Pune | 3 | INR | 4820.00 | |
| A-1042 | phone | 2026-02-03 | Daniel Roth | Leipzig | 1 | EUR | 96.50 | |
| A-1043 | web | 2026-02-04 | Sofia Duarte | Porto | 12 | EUR | 31.00 | 04002 |
Three levels of markup, nine columns, no cell holding a blob of angle brackets. The order element repeats under the root, so it became the record. id and channel were attributes on that element, so they kept their bare names with no @ bolted on the front. The customer block contributed customer.name and customer.city. And total split in two, because an element that carries an attribute and a value at once needs a column for each; the attribute is written first, which is why total.currency sits to the left of total.
Now look at the far right. customer.postcode is nowhere near the other customer fields, because record three is the first one that mentions it. Column names are the union of every record's fields in the order they were first seen, so a field that only some records carry lands at the end of the sheet and everything above it is blank. Dragging that column into place in Excel takes a second, and knowing to expect it saves you wondering whether the file was read correctly.
What the nesting turns into
A spreadsheet needs to know what one row is, and XML never says. The rule applied here is short: group the root's direct children by tag name, and the largest group is the records. A feed carrying one generator element beside 3,000 entry elements gives 3,000 rows, with the generator left out.
- Child elements become columns named with dots. A billing block inside each record produces
billing.streetandbilling.zip. - The dots run three levels below the record element. Past that, the branch is written into one cell as its own text and the widget prints a note counting how many places that happened in.
- An attribute takes the name of whatever it hangs off.
currencyon a nested total becomestotal.currency, while an attribute on the record element itself is justcurrency. - Only the root's own children are counted. If your records sit under response, then body, then rows, nothing repeats at the top level, so copy the inner fragment into the paste tab instead of feeding it the whole envelope.
- Namespace prefixes are removed before column names are built, so
g:pricebecomes a column called price.
What Excel does with the values
XML has no types. Every value in the document is text, so the writer decides cell by cell, and a cell only becomes numeric when the number would print back as exactly the same characters.
In the worked example, units is the only column Excel receives as numbers. 3, 1 and 12 all survive that round trip. 4820.00 does not, because a numeric cell would display 4820 and the two trailing digits would be gone, so the totals column arrives as text. 04002 stays text for the mirror-image reason: 4002 is a different postcode.
The rule is deliberately narrow. Order numbers, ISBNs, account codes and phone numbers reach the sheet with their padding intact, which is usually the damage people come here to undo. The cost is that a money column formatted to two decimals lands as text and wants one pass of Format Cells before you can sum it. Dates are never reinterpreted either. 2026-02-04 stays a string, because nothing in the file says which timezone whoever wrote it had in mind.
Documents that resist becoming a sheet
- Mixed content loses the loose words. Given
<note id="1">see <ref>A4</ref> for detail</note>you get a ref column holding A4, and the text around it is gone. Once an element has child elements it is read through those children only. Prose-shaped XML is the wrong input for a spreadsheet, and this is where that shows. - Two namespaces can share one column. Prefixes are stripped for readability, so a document that uses both dc:title and atom:title puts them in a single title column, and the one read later wins the cell.
- A single record still converts, with a warning. If the root has one child, you get a one-row workbook and a note saying the structure may not be tabular. That nearly always means the real records live a level deeper.
- Repeated children inside a record collapse. Three tag elements inside the same item write into one tag column and the last one is what you keep. Splitting those into separate rows is a job for the full editor.
- There is no copy button here. A workbook is binary, so this page offers a download and nothing else. To paste cells straight into a sheet that is already open, use the XML to table tool instead.
- 100 MB is the ceiling. No row cap and no daily quota below that. Above it the widget hands you to the full editor rather than pulling the whole document into memory at once.
Frequently Asked Questions
Does the XML get uploaded anywhere?
No. Your browser's own XML parser reads the document inside the tab, and the workbook is assembled there too. There is no endpoint on the other side of this page to send a file to.
How does it decide what counts as a row?
It groups the root element's direct children by tag name and takes the largest group. Three order elements under an orders root give you three rows, and a lone metadata sibling is left out.
What happens to nested elements?
They become dotted columns. A customer block inside each record produces customer.name and customer.city. Nesting is followed three levels below the record element, and anything deeper is written into a single cell as text with a note saying how many places that affected.
Will leading zeros survive the trip into Excel?
Yes. A value only becomes a numeric cell when the number would print back as identical characters, so 04002 and 0000000101 arrive as text. The trade is that 4820.00 is also written as text, because a number cell would show 4820.
Can I get an .xls file instead?
No. The download is .xlsx, the format Excel has used since 2007, and Numbers, LibreOffice and Google Sheets all open it without a plugin. The older .xls format is not offered.
Which sheet does the data land on?
One sheet named Sheet1, with the column names in row 1 and one record per row after that. The file keeps the name you gave it, so catalog.xml comes back as catalog.xlsx.
Related
Turn your XML into a workbook
Drop the file or paste a fragment. You get a preview of the columns first, then the .xlsx, with nothing leaving your machine.
Back to the converter