Chapters: JavaScript HTML & CSS JSON XML YAML ← Full TOC

📄 Chapter 33 — XML

Complete reference for XML — syntax, XPath navigation, Python parsing, XSLT transformations, and XSD schema validation with copy-paste examples.
Part of The Direct Path to Linux Ubuntu — free for all.

4Topics
96+Concepts
5Examples
xmlFormat
XML 1.0Standard
FreeNo login
📄 XML Syntax 🔍 XPath 🐍 Python xml 🔄 XSLT & XSD ⚡ Examples

📄 XML Syntax

📄 XML SyntaxElements, attributes, namespaces, and well-formed rules

🔍 XPath

🔍 XPathNavigate XML documents with XPath expressions

🐍 Python xml

🐍 Python xmlElementTree, minidom, lxml — parse and generate XML

🔄 XSLT & XSD

🔄 XSLT & XSDTransform XML with XSLT, validate with XSD schemas

⚡ Quick Examples

Run Python examples with python3 script.py.

Well-Formed XML Template

Production XML with namespaces and all syntax rules.

<?xml version="1.0" encoding="UTF-8"?>
<!-- MyWebUniversity — XML example document -->
<!-- Rules: close all tags, quote attributes, escape & < > -->
<catalog xmlns="https://www.mywebuniversity.com/catalog/v2"
         xmlns:dc="http://purl.org/dc/elements/1.1/"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://www.mywebuniversity.com/catalog/v2 catalog.xsd">

  <course id="CS101" level="beginner" available="true">
    <dc:title>Introduction to Python Programming</dc:title>
    <dc:creator>Dr. Alice Brown</dc:creator>
    <dc:date>2026-09-01</dc:date>
    <description>
      Learn Python from scratch: variables, loops, functions,
      and object-oriented programming. &amp; includes hands-on projects.
    </description>
    <!-- CDATA for content with special chars -->
    <code_sample><![CDATA[
def factorial(n):
    return 1 if n <= 1 else n * factorial(n-1)
print(factorial(10))  # Output: 3628800
    ]]></code_sample>
    <prerequisites/>  <!-- empty element -->
    <outcomes>
      <outcome>Write Python scripts</outcome>
      <outcome>Use standard library</outcome>
      <outcome>Understand OOP concepts</outcome>
    </outcomes>
    <price currency="USD" discount="0.00">0.00</price>
  </course>

</catalog>

Parse XML (Python ElementTree)

Read, navigate, and modify XML with Python's built-in library.

import xml.etree.ElementTree as ET

# Parse from string
xml = '''<library>
  <book id="1" available="true">
    <title>Learning Go</title>
    <author>Jon Bodner</author>
    <year>2021</year>
    <price>39.99</price>
  </book>
  <book id="2" available="false">
    <title>The Rust Programming Language</title>
    <author>Steve Klabnik</author>
    <year>2019</year>
    <price>29.99</price>
  </book>
  <book id="3" available="true">
    <title>Python Cookbook</title>
    <author>David Beazley</author>
    <year>2013</year>
    <price>49.99</price>
  </book>
</library>'''

root = ET.fromstring(xml)

# Find all books
for book in root.findall('book'):
    print(f"[{book.get('id')}] {book.findtext('title')} "
          f"by {book.findtext('author')} (${book.findtext('price')})")

# Filter: available only
print("\nAvailable:")
for b in root.findall("book[@available='true']"):
    print(f"  {b.findtext('title')}")

# Aggregate
prices = [float(b.findtext('price')) for b in root.findall('book')]
print(f"\nTotal: ${sum(prices):.2f}  Avg: ${sum(prices)/len(prices):.2f}")

# Add a new book
new = ET.SubElement(root, 'book', id='4', available='true')
ET.SubElement(new, 'title').text  = 'Designing Data-Intensive Applications'
ET.SubElement(new, 'author').text = 'Martin Kleppmann'
ET.SubElement(new, 'year').text   = '2017'
ET.SubElement(new, 'price').text  = '44.99'

ET.indent(root, space='  ')
print("\nAfter adding book 4:")
print(ET.tostring(root, encoding='unicode')[:300])
# python3 xml_parse.py

XML to JSON conversion (Python)

Convert XML documents to JSON format.

import xml.etree.ElementTree as ET
import json

def xml_to_dict(element):
    result = {}
    # Attributes
    if element.attrib:
        result.update({f"@{k}": v for k, v in element.attrib.items()})
    # Children
    children = list(element)
    if children:
        child_dict = {}
        for child in children:
            child_data = xml_to_dict(child)
            tag = child.tag
            if tag in child_dict:
                if not isinstance(child_dict[tag], list):
                    child_dict[tag] = [child_dict[tag]]
                child_dict[tag].append(child_data)
            else:
                child_dict[tag] = child_data
        result.update(child_dict)
    # Text content
    text = (element.text or '').strip()
    if text:
        if result:
            result['#text'] = text
        else:
            return text
    return result or None

xml_str = '''<students>
  <student id="1001" status="active">
    <name>Alice Smith</name>
    <gpa>3.95</gpa>
    <course grade="A">Python</course>
    <course grade="A-">JavaScript</course>
  </student>
  <student id="1002" status="active">
    <name>Bob Jones</name>
    <gpa>3.72</gpa>
    <course grade="B+">Python</course>
  </student>
</students>'''

root = ET.fromstring(xml_str)
data = {root.tag: xml_to_dict(root)}
print(json.dumps(data, indent=2))
# python3 xml_to_json.py

Generate XML Report (Python)

Create XML programmatically and write to file.

import xml.etree.ElementTree as ET
from datetime import date

def make_report(students):
    root = ET.Element('report',
        generated=date.today().isoformat(),
        version='1.0',
        source='MyWebUniversity'
    )
    summary = ET.SubElement(root, 'summary')
    ET.SubElement(summary, 'total').text     = str(len(students))
    ET.SubElement(summary, 'active').text    = str(sum(1 for s in students if s['active']))
    avg_gpa = sum(s['gpa'] for s in students) / len(students)
    ET.SubElement(summary, 'avg_gpa').text   = f"{avg_gpa:.3f}"

    students_el = ET.SubElement(root, 'students')
    for s in sorted(students, key=lambda x: -x['gpa']):
        st = ET.SubElement(students_el, 'student',
            id=str(s['id']),
            status='active' if s['active'] else 'inactive'
        )
        ET.SubElement(st, 'name').text    = s['name']
        ET.SubElement(st, 'email').text   = s['email']
        ET.SubElement(st, 'gpa').text     = str(s['gpa'])
        ET.SubElement(st, 'grade').text   = 'A' if s['gpa'] >= 3.7 else 'B'
        courses_el = ET.SubElement(st, 'courses')
        for c in s.get('courses', []):
            ET.SubElement(courses_el, 'course',
                code=c['code'], credits=str(c['credits'])
            ).text = c['name']
    return root

students = [
    {'id':1,'name':'Alice','email':'a@u.edu','gpa':3.95,'active':True,
     'courses':[{'code':'CS101','credits':3,'name':'Python'},
                {'code':'CS201','credits':3,'name':'JavaScript'}]},
    {'id':2,'name':'Bob',  'email':'b@u.edu','gpa':3.72,'active':True,
     'courses':[{'code':'CS101','credits':3,'name':'Python'}]},
    {'id':3,'name':'Carol','email':'c@u.edu','gpa':3.88,'active':False,
     'courses':[]},
]

root = make_report(students)
ET.indent(root, space='  ')
tree = ET.ElementTree(root)
tree.write('report.xml', encoding='utf-8', xml_declaration=True)
print("Written report.xml:")
print(ET.tostring(root, encoding='unicode')[:500])
# python3 generate_xml.py

XML Namespaces

Working with XML namespaces in Python.

import xml.etree.ElementTree as ET

# XML with multiple namespaces
xml = '''<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="https://mywebuniversity.com/default"
      xmlns:dc="http://purl.org/dc/elements/1.1/"
      xmlns:xlink="http://www.w3.org/1999/xlink">

  <course id="CS101">
    <dc:title>Introduction to Python</dc:title>
    <dc:creator>Dr. Brown</dc:creator>
    <dc:date>2026-09-01</dc:date>
    <resource xlink:href="https://mywebuniversity.com/python"
              xlink:type="simple">Course Materials</resource>
  </course>

</root>'''

# Register namespaces for cleaner output
ET.register_namespace('',     'https://mywebuniversity.com/default')
ET.register_namespace('dc',   'http://purl.org/dc/elements/1.1/')
ET.register_namespace('xlink','http://www.w3.org/1999/xlink')

root = ET.fromstring(xml)

# Must use Clark notation {uri}localname with ElementTree
NS = {
    '':      'https://mywebuniversity.com/default',
    'dc':    'http://purl.org/dc/elements/1.1/',
    'xlink': 'http://www.w3.org/1999/xlink',
}

for course in root.findall('{https://mywebuniversity.com/default}course'):
    cid   = course.get('id')
    title = course.findtext('{http://purl.org/dc/elements/1.1/}title')
    res   = course.find('{https://mywebuniversity.com/default}resource')
    href  = res.get('{http://www.w3.org/1999/xlink}href') if res is not None else ''
    print(f"  [{cid}] {title}")
    print(f"         Link: {href}")

print("\nNote: Use lxml for cleaner namespace handling with XPath")
# pip install lxml
# from lxml import etree
# tree = etree.fromstring(xml.encode())
# ns = {'dc':'http://purl.org/dc/elements/1.1/','u':'https://mywebuniversity.com/default'}
# print(tree.xpath('//dc:title/text()', namespaces=ns))
# python3 namespaces.py