Select XML children with a namespace map

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

Comments

Popular posts from this blog

Compare Two Text Files in Python Without Modifying Them

Seven CSV Quality Checks to Run Before Importing Data

Explain why SQLite transactions cannot make an HTTP call atomic