Select XML children with a namespace map
Also published in our Blogger archive.
XML namespace prefixes in a document are not the names that ElementTree stores internally. It expands namespaced tags to URI-qualified names. A namespace map lets a query use readable local prefixes while supplying the full namespace URI separately. This example parses a short catalog with one default namespace and one meta namespace, then calls findall() with paths that use the map.
The map names are chosen by the program; they do not need to match the prefixes used in the XML source. root.findall('book:item', ns) selects the two default-namespace items. On each item, item.find('meta:code', ns) selects its namespaced child. The assertions confirm the two titles and codes, while the output pairs each title with its corresponding code in document order.
This approach uses ElementTree’s supported XPath subset, not a complete XPath engine. A query must include the namespace map for each namespaced path, and an unqualified findall('item') would not select these default-namespaced elements. The example assumes every selected item has one meta:code child; a general parser should handle None from find() deliberately. It also parses a fixed trusted fixture only. For untrusted XML, review the XML security notes linked from the standard-library documentation.
Python explains namespace expansion and namespace-map queries in the Python xml.etree.ElementTree documentation.
AI assistance disclosure: AI helped draft this educational example; its assertions should still be run in the target environment.
import xml.etree.ElementTree as ET
xml_text = """<catalog xmlns="urn:books" xmlns:meta="urn:meta">
<item><title>Orbit</title><meta:code>O-1</meta:code></item>
<item><title>River</title><meta:code>R-2</meta:code></item>
</catalog>"""
root = ET.fromstring(xml_text)
ns = {"book": "urn:books", "meta": "urn:meta"}
items = root.findall("book:item", ns)
records = [
(item.find("book:title", ns).text, item.find("meta:code", ns).text)
for item in items
]
assert len(items) == 2
assert records == [("Orbit", "O-1"), ("River", "R-2")]
print("; ".join(f"{title}:{code}" for title, code in records))
Orbit:O-1; River:R-2