Python's built-in xml.etree.ElementTree handles most XML needs. For XPath 1.0, XSLT, and DTD validation, use lxml. For small documents or pretty-printing, use xml.dom.minidom.
| Item | Syntax / Value | Description |
|---|---|---|
| ET.parse | ET.parse('file.xml') → ElementTree | Parse XML file |
| ET.fromstring | ET.fromstring(xml_string) → Element | Parse XML string to root Element |
| ET.tostring | ET.tostring(element, encoding='unicode') → str | Serialize Element to string |
| tree.getroot | tree.getroot() → Element | Get root element |
| element.tag | element.tag → str | Element tag name (with namespace) |
| element.text | element.text → str | Text content of element |
| element.tail | element.tail → str | Text after closing tag |
| element.attrib | element.attrib → dict | All attributes as dictionary |
| element.get | element.get('attr', default) → str | Get attribute value |
| element.set | element.set('attr', 'value') | Set attribute value |
| element.find | element.find('tag') → Element | Find first matching child |
| element.findall | element.findall('tag') → [Element] | Find all matching children |
| element.findtext | element.findtext('tag') → str | Get text of first matching child |
| element.iter | element.iter('tag') → iterator | Recursively iterate matching elements |
| element.append | element.append(child) | Append child element |
| element.remove | element.remove(child) | Remove child element |
| ET.SubElement | ET.SubElement(parent, 'tag', attrib={}) → Element | Create and append child |
| ET.Element | ET.Element('tag', attrib={}) → Element | Create new element |
| ET.indent | ET.indent(element, space=' ') | Pretty-print indent (Python 3.9+) |
| tree.write | tree.write('out.xml', encoding='utf-8', xml_declaration=True) | Write to file |
| minidom.parseString | minidom.parseString(xml_bytes).toprettyxml() | Pretty-print XML |
| lxml.etree.parse | lxml.etree.parse(file) | lxml — full XPath, XSLT, validation |
| lxml.xpath | element.xpath('//tag', namespaces={}) | lxml — XPath with namespaces |
import xml.etree.ElementTree as ET
import xml.dom.minidom as minidom
from pathlib import Path
# ── 1. Parse XML ─────────────────────────────────────────────
xml_data = """<?xml version="1.0" encoding="UTF-8"?>
<students>
<student id="1001" status="active">
<name>Alice Smith</name>
<email>alice@mywebuniversity.com</email>
<gpa>3.95</gpa>
<courses>
<course code="CS101" credits="3" grade="A">Python</course>
<course code="CS201" credits="3" grade="A-">JavaScript</course>
<course code="CS301" credits="4" grade="A+">Data Science</course>
</courses>
</student>
<student id="1002" status="active">
<name>Bob Jones</name>
<email>bob@mywebuniversity.com</email>
<gpa>3.72</gpa>
<courses>
<course code="CS101" credits="3" grade="B+">Python</course>
</courses>
</student>
</students>"""
root = ET.fromstring(xml_data)
# ── 2. Navigate & extract ─────────────────────────────────────
print("=== All students ===")
for student in root.findall('student'):
sid = student.get('id')
name = student.findtext('name')
gpa = float(student.findtext('gpa'))
courses = student.findall('courses/course')
credits = sum(int(c.get('credits',0)) for c in courses)
print(f" [{sid}] {name} GPA={gpa} Credits={credits}")
# ── 3. Filter & search ────────────────────────────────────────
print("\n=== GPA >= 3.9 ===")
for s in root.iter('student'):
if float(s.findtext('gpa', '0')) >= 3.9:
print(f" {s.findtext('name')} — {s.findtext('gpa')}")
print("\n=== All A+ courses ===")
for c in root.iter('course'):
if c.get('grade') == 'A+':
print(f" {c.text} (code={c.get('code')})")
# ── 4. Modify XML ─────────────────────────────────────────────
# Add new student
new_student = ET.SubElement(root, 'student', id='1003', status='active')
ET.SubElement(new_student, 'name').text = 'Carol Davis'
ET.SubElement(new_student, 'email').text = 'carol@mywebuniversity.com'
ET.SubElement(new_student, 'gpa').text = '3.88'
courses_el = ET.SubElement(new_student, 'courses')
ET.SubElement(courses_el, 'course', code='CS101', credits='3', grade='A').text = 'Python'
# ── 5. Pretty-print & write ───────────────────────────────────
ET.indent(root, space=' ') # Python 3.9+
output = ET.tostring(root, encoding='unicode', xml_declaration=False)
print("\n=== Pretty XML ===")
print('<?xml version="1.0" encoding="UTF-8"?>')
print(output[:600] + '...')
# Write to file
tree = ET.ElementTree(root)
tree.write('students_out.xml', encoding='utf-8', xml_declaration=True)
print("\nWritten to students_out.xml")
# ── 6. minidom pretty-print ───────────────────────────────────
raw = ET.tostring(root)
pretty = minidom.parseString(raw).toprettyxml(indent=' ')
print("\nminidom output (first 300 chars):")
print(pretty[:300])
Path('students_out.xml').unlink(missing_ok=True)
# python3 xml_demo.py