Batu Lab NotesPractical developer guides

Require an XML attribute before converting it

By Batu · English technical notes

Also published in our Blogger archive.

Require an XML attribute before converting it

An XML attribute is optional from ElementTree’s perspective: Element.get() returns None when the attribute is absent. Passing that value directly to int() produces a less useful conversion error and obscures which field violated the document contract. Check for None first, then convert the present string.

This example parses two synthetic <job> elements. The first has retries="3", so required_int_attribute() returns the integer 3. The second has no retries attribute; the helper raises a deliberate ValueError that names the missing attribute. The assertions verify both outcomes before the example prints them. A present but non-numeric value, such as retries="many", still reaches int() and raises its normal ValueError; add separate validation if the allowed format is more restrictive.

Element.get() is appropriate here because an absent attribute and an attribute whose value is an empty string are different cases. This check does not validate an XML schema, detect duplicate attributes, or establish that XML from an untrusted source is safe to parse. ElementTree’s documentation describes get() as attribute access and directs users handling untrusted data to its XML-security guidance. This uses APIs available in all currently supported Python versions.

AI assistance disclosure: this article was drafted with AI assistance and should be reviewed for its application-specific XML rules.

Source: Python ElementTree documentation.

import xml.etree.ElementTree as ET


def required_int_attribute(element, name):
    raw_value = element.get(name)
    if raw_value is None:
        raise ValueError(f"missing required attribute: {name}")
    return int(raw_value)


complete = ET.fromstring('<job retries="3" />')
missing = ET.fromstring('<job />')

retries = required_int_attribute(complete, "retries")
assert retries == 3

try:
    required_int_attribute(missing, "retries")
except ValueError as error:
    assert str(error) == "missing required attribute: retries"
    print(f"count={retries}")
    print(f"error={error}")
else:
    raise AssertionError("a missing attribute must be rejected")
count=3
error=missing required attribute: retries