Skip to content

gh-61290: Fix serializing attributes with the default_namespace option - #156747

Open
serhiy-storchaka wants to merge 2 commits into
python:mainfrom
serhiy-storchaka:gh-61290-default-namespace-attrs
Open

gh-61290: Fix serializing attributes with the default_namespace option#156747
serhiy-storchaka wants to merge 2 commits into
python:mainfrom
serhiy-storchaka:gh-61290-default-namespace-attrs

Conversation

@serhiy-storchaka

@serhiy-storchaka serhiy-storchaka commented Aug 31, 2026

Copy link
Copy Markdown
Member

Serialization with the default_namespace option failed for any attribute without a namespace:

>>> svg = ET.XML('<svg xmlns="http://www.w3.org/2000/svg"><rect fill="none"/></svg>')
>>> ET.tostring(svg, default_namespace='http://www.w3.org/2000/svg')
ValueError: cannot use non-qualified names with default_namespace option

But a default namespace declaration does not apply to attribute names (Namespaces in XML, 6.2), so an unqualified attribute name can be written as is. For the same reason a qualified attribute name always needs a prefix, even if it is in the default namespace, and its namespace has to be declared twice:

>>> e = ET.Element('{uri}svg', {'{uri}id': 'a'})
>>> ET.tostring(e, encoding='unicode', default_namespace='uri')
'<svg xmlns="uri" xmlns:ns1="uri" ns1:id="a" />'

lxml serializes it the same way. Attribute names are now encoded separately from element names, and the namespaces table maps prefixes to URIs, because one URI can need both the default declaration and a prefixed one.

This also fixes gh-113581, the same bug seen from the other side: a qualified attribute name in the default namespace was written without a prefix, so its namespace was silently lost when the document was parsed back.

… option

The default namespace declaration does not apply to attribute names, so an
unqualified attribute name can be written as is, and a qualified attribute
name always needs a prefix, even if it is in the default namespace.  They
are now encoded separately from element names, and the namespaces table maps
prefixes to URIs, because a URI can need both the default declaration and a
prefixed one.
register_namespace("", uri) still makes it the default namespace, unless the
default_namespace option is used for other uri.  Serializing such tree no
longer produces two xmlns attributes (pythongh-118416).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ElementTree.tostring(..., default_namespace=...) incorrectly strips namespace from attributes

1 participant