How to convert XML to CSV
Drop your .xml file into the converter at the top of this page (or paste the markup). The tool parses the document with the browser’s DOMParser, finds the most-repeated element, and turns each occurrence into a CSV row. Runs entirely client-side — no upload.
- Upload or paste your XML. Drag a
.xml,.rss, or.atomfile in, or paste the markup directly. - Confirm the row element. The dropdown lists every element name that appears more than once, sorted by frequency. The most common one is auto-selected — that’s almost always what you want.
- Inspect the headers. Columns are the union of child element names and attributes across all rows. Attributes are prefixed with
@. Missing values become empty cells. - Pick a delimiter (comma, semicolon, tab) and copy or download the CSV.
CSV is inherently flat, so deeply nested XML gets flattened — see “Handling nested XML” below for the trade-offs.
XML to CSV examples
RSS feed → CSV
Given this RSS 2.0 fragment:
<rss version="2.0">
<channel>
<title>Example Blog</title>
<item>
<title>Hello world</title>
<link>https://example.com/posts/1</link>
<pubDate>Mon, 01 Jan 2024 12:00:00 GMT</pubDate>
<guid isPermaLink="true">https://example.com/posts/1</guid>
</item>
<item>
<title>Second post</title>
<link>https://example.com/posts/2</link>
<pubDate>Tue, 02 Jan 2024 12:00:00 GMT</pubDate>
<guid isPermaLink="true">https://example.com/posts/2</guid>
</item>
</channel>
</rss>
The auto-detected row element is <item> (2 occurrences vs 1 for <channel> and <rss>). Output:
title,link,pubDate,guid@isPermaLink,guid
Hello world,https://example.com/posts/1,"Mon, 01 Jan 2024 12:00:00 GMT",true,https://example.com/posts/1
Second post,https://example.com/posts/2,"Tue, 02 Jan 2024 12:00:00 GMT",true,https://example.com/posts/2
The isPermaLink attribute on <guid> is preserved as the guid@isPermaLink column.
sitemap.xml → CSV
Given a standard sitemap:
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://example.com/</loc>
<lastmod>2024-03-12</lastmod>
<changefreq>daily</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://example.com/about</loc>
<lastmod>2024-02-08</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
</urlset>
Row element is <url>. Output:
loc,lastmod,changefreq,priority
https://example.com/,2024-03-12,daily,1.0
https://example.com/about,2024-02-08,monthly,0.7
The xmlns namespace is ignored — the converter matches by local name, so <sitemap:url> would work the same way.
Generic data XML → CSV
Given a SOAP-style response or exported record set:
<Customers>
<Customer id="C-001" status="active">
<Name>Ada Lovelace</Name>
<Email>ada@lovelace.io</Email>
<Address>
<Street>1 Mathematics Way</Street>
<City>London</City>
</Address>
</Customer>
<Customer id="C-002" status="inactive">
<Name>Linus Torvalds</Name>
<Email>linus@kernel.example</Email>
</Customer>
</Customers>
Output:
@id,@status,Name,Email,Address
C-001,active,Ada Lovelace,ada@lovelace.io,1 Mathematics Way London
C-002,inactive,Linus Torvalds,linus@kernel.example,
Attributes on <Customer> become @id and @status. The nested <Address> block is flattened — its descendant text is joined into a single Address cell. The second row has no <Address>, so that cell is empty.
Handling nested XML and attributes
CSV is two-dimensional. XML is a tree. The converter flattens the tree using these rules:
- Direct children of the row element become columns named after the child tag.
- Attributes on the row element become columns prefixed with
@(e.g.@id). - Attributes on direct children become columns named
<child>@<attr>(e.g.link@hreffor Atom feeds). - Grandchildren and deeper are not given their own columns. Their text content is joined into the parent column, separated by spaces.
- Repeated siblings (e.g. multiple
<category>tags inside one<item>) are joined with|so you don’t lose data.
If your XML has deeply nested structure that matters (e.g. <order><lineItem><product><sku> × N), CSV is the wrong target. Convert to JSON first and work from there:
# xq is part of yq — preserves the full tree
xq . orders.xml > orders.json
Then use a JSON-to-CSV converter with the right path expression to pull out the rows you want.
How to convert XML to CSV in Python / Excel / pandas
Python with xml.etree.ElementTree (stdlib)
import csv
import xml.etree.ElementTree as ET
tree = ET.parse("feed.xml")
items = tree.findall(".//item")
# Collect the union of child tags as headers
headers = []
seen = set()
for it in items:
for child in it:
if child.tag not in seen:
headers.append(child.tag)
seen.add(child.tag)
with open("feed.csv", "w", newline="") as f:
w = csv.DictWriter(f, fieldnames=headers)
w.writeheader()
for it in items:
w.writerow({c.tag: (c.text or "").strip() for c in it})
Python with pandas.read_xml (pandas ≥ 1.3)
import pandas as pd
df = pd.read_xml("feed.xml", xpath=".//item")
df.to_csv("feed.csv", index=False)
read_xml is the one-liner. It only handles direct children — attributes need attrs_only=True or a custom XSLT. For sitemaps with the default namespace, pass namespaces={"s": "http://www.sitemaps.org/schemas/sitemap/0.9"} and xpath=".//s:url".
Excel — Power Query / “From XML”
In Excel Data → Get Data → From File → From XML. Excel surfaces a navigator listing repeating elements. Pick the one you want, click Transform Data in Power Query, expand nested columns by clicking the ⇆ icon next to each, then Close & Load. Save As → CSV.
This is the right path for one-off XML files when you don’t want to write code. Slow on files above ~10 MB.
Command-line with xq (jq for XML)
xq -r '.rss.channel.item | map([.title, .link, .pubDate]) | .[] | @csv' feed.xml > feed.csv
Best for shell pipelines and CI jobs. Add a header row by hand or with echo "title,link,pubDate" | cat - feed.csv.
Common XML-to-CSV problems
”My namespaces are breaking the parser”
XML with default namespaces (xmlns="..." on the root) require namespace-aware XPath in Python, but not in this converter — it matches by local name. If tree.findall(".//item") returns nothing in Python, the fix is either to register the namespace prefix (namespaces={"s": "..."} + .//s:item) or to strip namespaces before parsing.
”Mixed content gets mangled”
XML allows text and child elements to interleave inside the same parent (<p>Hello <b>world</b>!</p>). When that parent becomes a CSV cell, the converter joins all text with spaces, so you’ll see Hello world ! — readable, but not lossless. If interleaving matters (it usually means the data is documents, not records), CSV is the wrong format.
”Encoding errors / weird characters”
XML files declare their encoding in the prolog (<?xml version="1.0" encoding="UTF-8"?>). The browser respects that declaration for files you upload. If you’re seeing mojibake (é instead of é), open the file in a text editor and check the actual bytes match the declared encoding — files mis-saved as Latin-1 with a UTF-8 declaration are the most common cause. Re-save as UTF-8 and re-upload.
”Empty rows or wrong row element picked”
The auto-detect picks the most frequent repeating element. If your XML has more <tag> than <item> elements (e.g. a feed where every item has 5 categories), the dropdown will offer tag first. Just pick item from the dropdown — the order is by frequency but every repeating element is listed.
Privacy: nothing is uploaded
Parsing runs entirely in your browser using the built-in DOMParser and PapaParse for CSV output. Your XML never leaves your machine — verify in DevTools → Network. Useful for SOAP responses with internal IDs, exported customer feeds, or any XML you wouldn’t paste into a public converter.
Going the other way? See CSV to XML. To inspect the resulting CSV in a sortable table, use the CSV viewer. For trees that don’t flatten cleanly to CSV, JSON to CSV gives you path-based control over which fields become columns.
Related tools
Convert any CSV file to a real .xlsx Excel workbook in seconds. Free, no signup, files never leave your browser.
Turn any .xlsx or .xls Excel file into a clean CSV. Pick the sheet, pick the delimiter, download. No upload.
Convert any Excel workbook (.xlsx or .xls) to a printable PDF in seconds. Pick the sheet, pick orientation, download. 100% private.
Convert any CSV file to a clean PDF table in seconds. Free, no signup, files never leave your browser.
Frequently asked questions
- How do I convert XML to CSV?
Drop your .xml file (or paste the XML) into the converter at the top of this page. The tool auto-detects the repeating element — <item> for RSS, <url> for sitemaps, <record> or <row> for generic data — and turns each one into a CSV row. Child element text becomes column values; XML attributes show up as columns prefixed with @.
- How does it handle nested XML?
Direct child elements of the row element become columns. Deeper nesting (grandchildren) is flattened by joining all descendant text into one cell. If you need full nested structure preserved, convert XML → JSON first (jq, xmltodict) and use a JSON-to-CSV tool, since CSV is inherently flat.
- What about XML namespaces (xmlns)?
The converter matches elements by local name, so <atom:entry> and <entry> are treated the same. Namespace prefixes are stripped from column headers — useful for Atom feeds, SOAP envelopes, and Office Open XML.
- Are XML attributes included?
Yes. Attributes on the row element appear as columns prefixed with @ (for example @id, @type). Attributes on child elements appear as <child>@<attr> (for example link@href in Atom feeds where the URL lives in an attribute, not text).
- Can I convert large XML files?
The converter parses the whole document in memory using the browser's DOMParser, which handles files up to ~50–100 MB on a modern laptop. For multi-gigabyte XML dumps (Wikipedia, Stack Exchange data dumps), use a streaming parser like Python's lxml.etree.iterparse or xml-stream in Node — see the article below.
- Can I parse RSS feeds and sitemaps with this?
Yes — those are the two most common cases. RSS feeds use <item> as the repeating element; sitemap.xml uses <url>; Atom feeds use <entry>. The auto-detect picks the right one. For RSS you'll get title/link/pubDate/description columns; for sitemaps you'll get loc/lastmod/changefreq/priority.
- Does it handle CDATA sections and HTML inside XML?
Yes. CDATA content (often used in RSS <description> for HTML markup) is read as text and ends up in the cell verbatim. Internal whitespace is collapsed. If you need to strip HTML tags from the result, run the CSV through a quick find-and-replace or a script — the converter keeps content faithful by default.
- Is my XML uploaded?
No. Parsing runs entirely in your browser via DOMParser and PapaParse. The XML never leaves your machine — verify in DevTools → Network. Useful for internal SOAP responses, exported customer data, or anything you wouldn't paste into a public site.