pythonxmlelementtree

Using default_namespace argument of ElementTree.tostring throws error


I want to use ElementTree to modify an XML-document and to keep it comparable, I want to have the same namespace-prefixes in the new file as in the old file.

However, the default_namespace= argument of ET.tostring and ET.write causes errors with even simple documents.

Here is an example:

Example test.xml file:

<?xml version="1.0"?>
<test xmlns="http://www.example.com/blabla/">
  <item name="first" />
</test>

Test:

Python 3.11.5 (tags/v3.11.5:cce6ba9, Aug 24 2023, 14:38:34) [MSC v.1936 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import xml.etree.ElementTree as ET
>>> xml = ET.parse("test.xml")
>>> ET.tostring(xml, default_namespace="http://www.example.com/blabla/")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python311\Lib\xml\etree\ElementTree.py", line 1098, in tostring
    ElementTree(element).write(stream, encoding,
  File "C:\Python311\Lib\xml\etree\ElementTree.py", line 741, in write
    qnames, namespaces = _namespaces(self._root, default_namespace)
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\xml\etree\ElementTree.py", line 856, in _namespaces
    add_qname(key)
  File "C:\Python311\Lib\xml\etree\ElementTree.py", line 833, in add_qname
    raise ValueError(
ValueError: cannot use non-qualified names with default_namespace option

Is there any way to write the XML-File the way it is shown?


Solution

  • You have to use register_namespace(): See also the xml.etree.ElementTree documentation.

    import xml.etree.ElementTree as ET
    
    xml_ = """\
    <?xml version="1.0"?>
    <test xmlns="http://www.example.com/blabla/">
      <item name="first" />
    </test>"""
    
    root = ET.fromstring(xml_)
    ET.register_namespace('','http://www.example.com/blabla/')
    
    tree = ET.ElementTree(root)
    ET.indent(tree, space='  ')
    tree.write("out.xml", xml_declaration=True, encoding='utf-8')
    
    ET.dump(tree)
    # Alternative to dump
    # print(ET.tostring(root).decode())
    

    Output:

    <test xmlns="http://www.example.com/blabla/">
      <item name="first" />
    </test>