title: Why does ElementTree eat/ignore namespaces (in attribute values)?
body: <p>I'm trying to read XML with <code>ElementTree</code> and write the result back to disk. My long-term goal is to prettify the XML this way. However, in my naive approach, ElementTree eats all the namespace declarations in the document and I don't understand why. Here is an example</p>
  <p><strong>test.xsd</strong></p>
  <pre class="lang-xml prettyprint-override"><code>&lt;?xml version='1.0' encoding='UTF-8'?&gt;
  &lt;xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
      xmlns='sdformat/pose' targetNamespace='sdformat/pose'
      xmlns:pose='sdformat/pose'
      xmlns:types='http://sdformat.org/schemas/types.xsd'&gt;
  
  &lt;xs:import namespace='sdformat/pose' schemaLocation='./pose.xsd'/&gt;
  
  &lt;xs:element name='pose' type='poseType' /&gt;
  
  &lt;xs:simpleType name='string'&gt;&lt;xs:restriction base='xs:string' /&gt;&lt;/xs:simpleType&gt;
  &lt;xs:simpleType name='pose'&gt;&lt;xs:restriction base='types:pose' /&gt;&lt;/xs:simpleType&gt;
  
  &lt;xs:complexType name='poseType'&gt;
      &lt;xs:simpleContent&gt;
        &lt;xs:extension base=&quot;pose&quot;&gt;
      &lt;xs:attribute name='relative_to' type='string' use='optional' default=''&gt;
      &lt;/xs:attribute&gt;
  
        &lt;/xs:extension&gt;
      &lt;/xs:simpleContent&gt;
  &lt;/xs:complexType&gt;
  
  
  &lt;/xs:schema&gt;
  </code></pre>
  <p><strong>test.py</strong></p>
  <pre class="lang-py prettyprint-override"><code>from xml.etree import ElementTree
  
  ElementTree.register_namespace(&quot;types&quot;, &quot;http://sdformat.org/schemas/types.xsd&quot;)
  ElementTree.register_namespace(&quot;pose&quot;, &quot;sdformat/pose&quot;)
  ElementTree.register_namespace(&quot;xs&quot;, &quot;http://www.w3.org/2001/XMLSchema&quot;)
  
  tree = ElementTree.parse(&quot;test.xsd&quot;)
  tree.write(&quot;test_out.xsd&quot;)
  </code></pre>
  <p>Produces <strong>test_out.xsd</strong></p>
  <pre class="lang-xml prettyprint-override"><code>&lt;xs:schema xmlns:xs=&quot;http://www.w3.org/2001/XMLSchema&quot; targetNamespace=&quot;sdformat/pose&quot;&gt;
  
  &lt;xs:import namespace=&quot;sdformat/pose&quot; schemaLocation=&quot;./pose.xsd&quot; /&gt;
  
  &lt;xs:element name=&quot;pose&quot; type=&quot;poseType&quot; /&gt;
  
  &lt;xs:simpleType name=&quot;string&quot;&gt;&lt;xs:restriction base=&quot;xs:string&quot; /&gt;&lt;/xs:simpleType&gt;
  &lt;xs:simpleType name=&quot;pose&quot;&gt;&lt;xs:restriction base=&quot;types:pose&quot; /&gt;&lt;/xs:simpleType&gt;
  
  &lt;xs:complexType name=&quot;poseType&quot;&gt;
      &lt;xs:simpleContent&gt;
        &lt;xs:extension base=&quot;pose&quot;&gt;
      &lt;xs:attribute name=&quot;relative_to&quot; type=&quot;string&quot; use=&quot;optional&quot; default=&quot;&quot;&gt;
      &lt;/xs:attribute&gt;
  
        &lt;/xs:extension&gt;
      &lt;/xs:simpleContent&gt;
  &lt;/xs:complexType&gt;
  
  
  &lt;/xs:schema&gt;
  </code></pre>
  <p>Notice how <strong>test_out.xsd</strong> is missing any namespace declarations from <strong>test.xsd</strong>. I would expect them to be identical. I verified that the latter is valid XML by validating it. It validates with exception of my choice of namespace URI, which I think shouldn't matter.</p>
  <hr />
  <p><strong>Update:</strong></p>
  <p>Based on mzji's comment I realized that this only happens for values of attributes. With this in mind, I can manually add the namespaces like so:</p>
  <pre class="lang-py prettyprint-override"><code>from xml.etree import ElementTree
  
  namespaces = {
      &quot;types&quot;: &quot;http://sdformat.org/schemas/types.xsd&quot;,
      &quot;pose&quot;: &quot;sdformat/pose&quot;,
      &quot;xs&quot;: &quot;http://www.w3.org/2001/XMLSchema&quot;
  }
  
  for prefix, ns in namespaces.items():
      ElementTree.register_namespace(prefix, ns)
  
  tree = ElementTree.parse(&quot;test.xsd&quot;)
  root = tree.getroot()
  
  queue = [tree.getroot()]
  while queue:
      element:ElementTree.Element = queue.pop()
      for value in element.attrib.values():
          try:
              prefix, value = value.split(&quot;:&quot;)
          except ValueError:
              # no namespace, nothing to do
              pass
          else:
              if prefix == &quot;xs&quot;:
                  break  # ignore XMLSchema namespace
              root.attrib[f&quot;xmlns:{prefix}&quot;] = namespaces[prefix]
  
      for child in element:
          queue.append(child)
  
  tree.write(&quot;test_out.xsd&quot;)
  </code></pre>
  <p>While this solves the problem, it is quite an ugly solution. I also still don't understand why this happens in the first place, so it doesn't answer the question.</p>