How to convert XML to CSV in Python

XML to CSV comes down to two choices: which element is a row, and how nested data becomes columns. This script takes the row element as an argument and flattens everything inside it, using only the standard library.

1. The script

Save as xml2csv.py:

import csv, sys
import xml.etree.ElementTree as ET

def local(tag):  # '{http://www.sitemaps.org/schemas/sitemap/0.9}loc' -> 'loc'
    return tag.rsplit('}', 1)[-1]

def flatten(el, prefix=''):
    row = {f'{prefix or local(el.tag)}@{local(k)}': v for k, v in el.attrib.items()}
    seen = {}
    for child in el:
        name = local(child.tag)
        seen[name] = seen.get(name, 0) + 1
        key = prefix + name + (f'_{seen[name]}' if seen[name] > 1 else '')
        if len(child):
            row.update(flatten(child, key + '/'))
        else:
            row.update({f'{key}@{local(k)}': v for k, v in child.attrib.items()})
            if (child.text or '').strip() or not child.attrib:
                row[key] = (child.text or '').strip()
    return row

root = ET.parse(sys.argv[1]).getroot()
record = sys.argv[2]  # the repeating element, e.g. item (RSS) or url (sitemap)
rows = [flatten(el) for el in root.iter() if local(el.tag) == record]
columns = list(dict.fromkeys(k for r in rows for k in r))
with open(sys.argv[3], 'w', newline='', encoding='utf-8-sig') as f:
    w = csv.DictWriter(f, fieldnames=columns)
    w.writeheader()
    w.writerows(rows)
print(f'{len(rows)} <{record}> rows, {len(columns)} columns -> {sys.argv[3]}')

2. Run it

curl -sL https://www.sitemaps.org/sitemap.xml -o sitemap.xml
python3 xml2csv.py sitemap.xml url sitemap.csv

Our run printed 84 <url> rows, 2 columns -> sitemap.csv:

loc,lastmod
https://www.sitemaps.org/,2016-11-21
https://www.sitemaps.org/protocol.html,2022-12-15

For an RSS feed, the row element is item: python3 xml2csv.py feed.xml item feed.csv. On the BBC News feed that gave 38 rows with title, description, link, guid, pubDate and the thumbnail's width, height and url.

3. How the columns are named

4. Limits

5. No code

Paste the XML into the free XML to CSV converter: it finds the repeating element itself, exports CSV, TSV, Markdown or .xlsx, and nothing is uploaded.

Frequently asked questions

Can I convert XML to CSV without pandas?

Yes. The script above uses only xml.etree.ElementTree and csv. With pandas 1.3+, pd.read_xml('file.xml', xpath='//item').to_csv('out.csv', index=False) works for flat records (it uses lxml unless you pass parser='etree'), but it does not flatten nested elements.

How do I find the row element?

Look for the element that repeats: item in RSS, url in a sitemap, entry in Atom, often record or row in exports. The browser tool lists every repeating element with its count.

Why do I get an empty CSV?

The row element name is wrong, or the file uses a default namespace and you matched the full tag. The script compares local names, so pass just the name, e.g. url.

Written with AI assistance. The script was run on 2026-10-01 with the Python 3 standard library on the BBC News RSS feed (38 items, 9 columns) and the sitemaps.org sitemap (84 URLs); every row matched the browser XML to CSV tool cell for cell. PlainTables is our extension; the other methods are free and built into Excel, Google Sheets and pandas.