diff -r 1f1498fe50e5 Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py Wed Dec 04 23:29:51 2013 +0100 +++ b/Lib/test/test_xml_etree.py Thu Dec 05 00:30:46 2013 -0800 @@ -1612,6 +1612,24 @@ ET.register_namespace('test10777', 'http://myuri/') ET.register_namespace('test10777', 'http://myuri/') + def test_issue17088(self): + # Unprefixed attributes are unqualified even if a default namespace is in + # effect. + e = ET.XML('' + '') + self.assertEqual(e.tag, '{space1}name1') + self.assertEqual(e[0].attrib, { 'attr': 'value2', '{space2}attr': 'value3' }) + + pi = b"\n" + self.assertEqual(serialize(e), + '' + '') + self.assertEqual(serialize(e, default_namespace="space1"), + '' + '') + #self.assertEqual(serialize(e, default_namespace="space2"), + # '' + # '') # -------------------------------------------------------------------- diff -r 1f1498fe50e5 Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py Wed Dec 04 23:29:51 2013 +0100 +++ b/Lib/xml/etree/ElementTree.py Thu Dec 05 00:30:46 2013 -0800 @@ -847,7 +847,7 @@ if default_namespace: namespaces[default_namespace] = "" - def add_qname(qname): + def add_qname(qname, is_attrname): # calculate serialized qname representation try: if qname[:1] == "{": @@ -862,10 +862,24 @@ if prefix: qnames[qname] = "%s:%s" % (prefix, tag) else: + # FIXME: (if is_attrname and prefix == ''): If an + # attribute name is in the default namespace, we + # will write it out without a prefix, which is + # incorrect (an unprefixed attribute is always + # unqualified, even if a default namespace is in + # effect). For completely correct behavior, we + # would need to emit both a default namespace + # declaration *and* a prefix declaration for the + # use of attributes. qnames[qname] = tag # default element else: - if default_namespace: - # FIXME: can this be handled in XML 1.0? + if default_namespace and not is_attrname: + # A default namespace can be undeclared + # (see http://www.w3.org/TR/REC-xml-names/#defaulting) + # but only by placing an xmlns="" attribute on the + # element and possibly re-declaring the default + # namespace for child elements. Our serializers + # can't do that. FIXME. raise ValueError( "cannot use non-qualified names with " "default_namespace option" @@ -879,22 +893,22 @@ tag = elem.tag if isinstance(tag, QName): if tag.text not in qnames: - add_qname(tag.text) + add_qname(tag.text, False) elif isinstance(tag, str): if tag not in qnames: - add_qname(tag) + add_qname(tag, False) elif tag is not None and tag is not Comment and tag is not PI: _raise_serialization_error(tag) for key, value in elem.items(): if isinstance(key, QName): key = key.text if key not in qnames: - add_qname(key) + add_qname(key, True) if isinstance(value, QName) and value.text not in qnames: - add_qname(value.text) + add_qname(value.text, False) text = elem.text if isinstance(text, QName) and text.text not in qnames: - add_qname(text.text) + add_qname(text.text, False) return qnames, namespaces def _serialize_xml(write, elem, qnames, namespaces,