Skip to content

XML Parsing in Python — Complete Guide with ElementTree and lxml

DodaTech Updated 2026-06-23 8 min read

In this tutorial, you'll learn about XML Parsing in Python. We cover key concepts, practical examples, and best practices.

XML parsing in Python lets you read, extract, modify, and create XML documents using libraries like ElementTree (built-in) and lxml, enabling everything from configuration file processing to web service data handling.

What You'll Learn

  • Parsing XML with Python's built-in ElementTree module
  • Using lxml for advanced parsing with XPath support
  • SAX and DOM parsing approaches for different use cases
  • Creating and modifying XML documents programmatically

Why XML Parsing in Python Matters

Python is one of the most common languages for processing XML data — from parsing RSS feeds and configuration files to handling SOAP responses and XML-based data interchange. Durga Antivirus Pro uses Python with lxml to parse XML threat signature files, extracting malware patterns and validating updates before applying them to the scan engine.

Learning Path

flowchart LR
  A[XML Basics] --> B[XPath Queries]
  B --> C[XML Parsing Python
You are here] C --> D[XML Parsing Java] D --> E[XML Parsing JavaScript]

Setup and Sample Data

No external installation needed for ElementTree — it's built into Python. For lxml, install separately:

pip install lxml

Sample XML file used throughout this guide:

<?xml version="1.0" encoding="UTF-8"?>
<library>
    <book category="fiction" id="b1">
        <title>The Hobbit</title>
        <author>J.R.R. Tolkien</author>
        <year>1937</year>
        <price currency="USD">12.99</price>
    </book>
    <book category="non-fiction" id="b2">
        <title>A Brief History of Time</title>
        <author>Stephen Hawking</author>
        <year>1988</year>
        <price currency="GBP">9.99</price>
    </book>
    <book category="fiction" id="b3">
        <title>1984</title>
        <author>George Orwell</author>
        <year>1949</year>
        <price currency="USD">10.99</price>
    </book>
</library>

Parsing with ElementTree

ElementTree is Python's standard XML parser:

import xml.etree.ElementTree as ET

# Parse from file
tree = ET.parse('library.xml')
root = tree.getroot()

# Root tag and attributes
print(f"Root: {root.tag}")
print(f"Number of books: {len(root.findall('book'))}")

# Iterate through books
for book in root.findall('book'):
    title = book.find('title').text
    author = book.find('author').text
    year = book.find('year').text
    price = book.find('price').text
    category = book.get('category')
    print(f"'{title}' by {author} ({year}) - ${price} [{category}]")

# Expected output:
# Root: library
# Number of books: 3
# 'The Hobbit' by J.R.R. Tolkien (1937) - $12.99 [fiction]
# 'A Brief History of Time' by Stephen Hawking (1988) - $9.99 [non-fiction]
# '1984' by George Orwell (1949) - $10.99 [fiction]

Modifying XML with ElementTree

You can modify existing XML and write it back:

import xml.etree.ElementTree as ET

tree = ET.parse('library.xml')
root = tree.getroot()

# Add a new book
new_book = ET.SubElement(root, 'book')
new_book.set('category', 'sci-fi')
new_book.set('id', 'b4')

ET.SubElement(new_book, 'title').text = 'Dune'
ET.SubElement(new_book, 'author').text = 'Frank Herbert'
ET.SubElement(new_book, 'year').text = '1965'
price_elem = ET.SubElement(new_book, 'price')
price_elem.text = '14.99'
price_elem.set('currency', 'USD')

# Update price of first book
first_book = root.find('book')
first_book.find('price').text = '13.99'

# Save to new file
tree.write('library_updated.xml', encoding='UTF-8', xml_declaration=True)
print("Updated library saved.")

# Verify
for book in root.findall('book'):
    print(f"{book.find('title').text}: ${book.find('price').text}")

# Expected output:
# Updated library saved.
# The Hobbit: $13.99
# A Brief History of Time: $9.99
# 1984: $10.99
# Dune: $14.99

Advanced Parsing with lxml

lxml provides full XPath support and better performance:

from lxml import etree

# Parse with lxml
tree = etree.parse('library.xml')

# Full XPath support
fiction_titles = tree.xpath("//book["@category"='fiction']/title/text()")
print("Fiction titles:", fiction_titles)

# Find books under $11
budget_books = tree.xpath("//book[price < 11]")
for book in budget_books:
    title = book.xpath("title/text()")[0]
    price = book.xpath("price/text()")[0]
    print(f"Budget book: {title} - ${price}")

# Complex query with axes
results = tree.xpath("//book[1]/following-sibling::book/title/text()")
print("Books after first:", results)

# Expected output:
# Fiction titles: ['The Hobbit', '1984']
# Budget book: A Brief History of Time - $9.99
# Budget book: 1984 - $10.99
# Books after first: ['A Brief History of Time', '1984']

Creating XML from Scratch

ElementTree can build XML documents from scratch:

import xml.etree.ElementTree as ET

# Create root
library = ET.Element('library')

# Add books
books_data = [
    {'title': 'The Hobbit', 'author': 'J.R.R. Tolkien', 'year': '1937',
     'price': '12.99', 'cat': 'fiction'},
    {'title': '1984', 'author': 'George Orwell', 'year': '1949',
     'price': '10.99', 'cat': 'fiction'},
]

for data in books_data:
    book = ET.SubElement(library, 'book')
    book.set('category', data['cat'])
    ET.SubElement(book, 'title').text = data['title']
    ET.SubElement(book, 'author').text = data['author']
    ET.SubElement(book, 'year').text = data['year']
    ET.SubElement(book, 'price').text = data['price']

# Create tree and write
tree = ET.ElementTree(library)
tree.write('output.xml', encoding='UTF-8', xml_declaration=True)

# Pretty-print (Python 3.9+)
ET.indent(tree, space='    ')
tree.write('output_pretty.xml', encoding='UTF-8', xml_declaration=True)
print("XML files created successfully.")

# Verify output
with open('output_pretty.xml', 'r') as f:
    print(f.read())

# Expected output:
# XML files created successfully.
# <?xml version='1.0' encoding='UTF-8'?>
# <library>
#     <book category="fiction">
#         <title>The Hobbit</title>
#         <author>J.R.R. Tolkien</author>
#         <year>1937</year>
#         <price>12.99</price>
#     </book>
#     <book category="fiction">
#         <title>1984</title>
#         <author>George Orwell</author>
#         <year>1949</year>
#         <price>10.99</price>
#     </book>
# </library>

SAX Parsing for Large Files

SAX is event-driven — it reads large XML files without loading the entire tree into memory:

import xml.sax

class BookHandler(xml.sax.ContentHandler):
    def __init__(self):
        self.current_tag = ""
        self.current_book = {}
        self.in_book = False

    def startElement(self, tag, attrs):
        self.current_tag = tag
        if tag == 'book':
            self.in_book = True
            self.current_book = {'category': attrs.get('category', ''),
                                 'id': attrs.get('id', '')}

    def characters(self, content):
        if self.in_book and self.current_tag in ('title', 'author', 'year', 'price'):
            self.current_book[self.current_tag] = content.strip()

    def endElement(self, tag):
        if tag == 'book':
            print(f"Book: {self.current_book.get('title', 'N/A')} "
                  f"by {self.current_book.get('author', 'N/A')}")
            self.in_book = False

# Parse with SAX
parser = xml.sax.make_parser()
handler = BookHandler()
parser.setContentHandler(handler)

# This uses very little memory even with huge files
parser.parse('library.xml')

# Expected output:
# Book: The Hobbit by J.R.R. Tolkien
# Book: A Brief History of Time by Stephen Hawking
# Book: 1984 by George Orwell

Security Angle

XML parsing in Python is vulnerable to XXE (XML External Entity) attacks if not properly configured. Python's ElementTree is safe by default in Python 3.7.1+, but lxml requires explicit configuration:

from lxml import etree

# Secure parser: disable entities and DTD
parser = etree.XMLParser(
    resolve_entities=False,
    no_network=True,
    dtd_validation=False,
    load_dtd=False
)

# Attempt to parse a potentially malicious file
try:
    tree = etree.parse('untrusted.xml', parser)
    print("Parsed safely with entities disabled.")
except etree.XMLSyntaxError as e:
    print(f"Parse error (XXE blocked): {e}")

# Expected output:
# Parsed safely with entities disabled.
# (If the XML contains XXE, the parser silently ignores entity references)

Durga Antivirus Pro uses secure parsers with all entity resolution disabled when scanning untrusted XML files from email attachments and downloaded archives.

Common Mistakes

1. Forgetting to strip whitespace from text content

elem.text includes surrounding whitespace. Always call .strip() on extracted text.

2. Using find instead of findall

find returns the first match. findall returns all matches. Confusing them leads to missing data.

3. Not handling namespaces

XML with namespaces requires the full {uri}tag syntax in ElementTree. Use lxml with xpath for simpler namespace handling.

4. Loading entire large files into memory

For files over 100MB, use SAX or iterparse to process incrementally instead of loading the full tree.

Practice Questions

  1. What is the difference between ElementTree and lxml? ElementTree is built-in but has limited XPath support. lxml is faster, supports full XPath 1.0, and has better namespace handling.

  2. When should you use SAX parsing instead of DOM? SAX is event-driven and memory-efficient for large files. Use SAX when the file is too big to fit in memory as a tree.

  3. How do you prevent XXE attacks in Python XML parsing? Disable entity resolution and DTD loading. Use the secure parser configuration in lxml or stick with ElementTree (safe in Python 3.7.1+).

Challenge: Write a Python script that reads an RSS feed XML, extracts the latest 5 articles, and outputs them as a formatted HTML snippet with clickable links and publication dates.

FAQ

Which Python library is best for XML parsing?

For basic needs, use the built-in xml.etree.ElementTree. For advanced XPath and better performance, use lxml.

How do I handle XML namespaces in Python ElementTree?

Use the full Clark notation: {http://namespace.uri}tag. In lxml, use xpath with namespace prefixes.

Can Python parse very large XML files?

Yes. Use xml.sax (SAX) or xml.etree.ElementTree.iterparse for streaming, memory-efficient parsing of large files.

What is the difference between DOM and SAX parsing?

DOM loads the entire XML tree into memory. SAX reads events (start/end tags) without storing the tree.

How do I create XML from scratch in Python?

Use xml.etree.ElementTree: create the root with ET.Element(), add children with ET.SubElement(), and write with ET.ElementTree().write().

Is ElementTree vulnerable to XXE?

In Python 3.7.1+, ElementTree is safe by default. Earlier versions may need explicit parser configuration to disable entity resolution.

Try It Yourself

Run this complete example that parses XML from a string:

import xml.etree.ElementTree as ET

xml_string = """<?xml version="1.0"?>
<books>
    <book><title>Learning Python</title><price>39.99</price></book>
    <book><title>XML Essentials</title><price>29.99</price></book>
</books>"""

root = ET.fromstring(xml_string)

total = 0
for book in root.findall('book'):
    title = book.find('title').text
    price = float(book.find('price').text)
    total += price
    print(f"{title}: ${price:.2f}")

print(f"Total: ${total:.2f}")

# Expected output:
# Learning Python: $39.99
# XML Essentials: $29.99
# Total: $69.98

What's Next

Tutorial What You'll Learn
XML Basics — Complete Guide Foundational XML concepts
XPath Explained — Querying XML Navigate XML documents with path expressions
XSLT Explained — Transform XML Transform XML into HTML and other formats

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Updated 2026-06-23.

What's Next

Congratulations on completing this XML Parsing in Python tutorial! Here's where to go from here:

  • Practice daily — Consistency is more important than long study sessions
  • Build a project — Create a script that processes RSS feeds using ElementTree
  • Explore related topics — Check out other XML tutorials in this category
  • Join the community — Discuss with other learners and share your progress

Remember: every expert was once a beginner. Keep coding!

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro