# HG changeset patch # Parent 32d3770c19586a67b5f60ec69e5bb5fd2d59b84d Issue #13378: use non global namespaces for the serializer. diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -1717,6 +1717,8 @@ >>> s = ET.SubElement(e, "{not-default}elem") >>> serialize(e, default_namespace="default") # 2 '' + >>> serialize(e, namespaces={"default": ""}) + '' >>> e = ET.Element("{default}elem") >>> s = ET.SubElement(e, "{default}elem") @@ -1724,6 +1726,9 @@ >>> serialize(e, default_namespace="default") # 3 Traceback (most recent call last): ValueError: cannot use non-qualified names with default_namespace option + >>> serialize(e, namespaces={"default": ""}) + Traceback (most recent call last): + ValueError: cannot use non-qualified names with default_namespace option """ @@ -1851,6 +1856,20 @@ >>> ET.register_namespace('test10777', 'http://myuri/') """ +def check_issue13378(): + """ + Pass specific, non-global namespaces to the serializer. + + >>> elem = ET.XML('') + >>> serialize(elem, namespaces={'http://localhost/house': 'house'}) + '' + >>> serialize(elem) + '' + >>> serialize(elem, namespaces={'http://localhost/house': 'home'}) + '' + + """ + # -------------------------------------------------------------------- diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -813,7 +813,8 @@ encoding=None, xml_declaration=None, default_namespace=None, - method=None): + method=None, + namespaces=None): # assert self._root is not None if not method: method = "xml" @@ -857,7 +858,11 @@ if method == "text": _serialize_text(write, self._root) else: - qnames, namespaces = _namespaces(self._root, default_namespace) + # if custom namespaces... + namespaces = dict(namespaces or {}) + if default_namespace: + namespaces[default_namespace] = "" + qnames = _qnames(self._root, namespaces) serialize = _serialize[method] serialize(write, self._root, qnames, namespaces) if file_or_filename is not file: @@ -870,17 +875,23 @@ # -------------------------------------------------------------------- # serialization support -def _namespaces(elem, default_namespace=None): +def _qnames(elem, namespaces): # identify namespaces used in this tree # maps qnames to *encoded* prefix:local names qnames = {None: None} + # any uri is mapped to ""? + has_default_namespace = ("" in namespaces.values()) + + if namespaces: + namespace_map = _namespace_map.copy() + namespace_map.update(namespaces) + namespaces.clear() + else: + namespace_map = _namespace_map + # maps uri:s to prefixes - namespaces = {} - if default_namespace: - namespaces[default_namespace] = "" - def add_qname(qname): # calculate serialized qname representation try: @@ -888,7 +899,7 @@ uri, tag = qname[1:].rsplit("}", 1) prefix = namespaces.get(uri) if prefix is None: - prefix = _namespace_map.get(uri) + prefix = namespace_map.get(uri) if prefix is None: prefix = "ns%d" % len(namespaces) if prefix != "xml": @@ -898,7 +909,7 @@ else: qnames[qname] = tag # default element else: - if default_namespace: + if has_default_namespace: # FIXME: can this be handled in XML 1.0? raise ValueError( "cannot use non-qualified names with " @@ -909,11 +920,7 @@ _raise_serialization_error(qname) # populate qname and namespaces table - try: - iterate = elem.iter - except AttributeError: - iterate = elem.getiterator # cET compatibility - for elem in iterate(): + for elem in elem.iter(): tag = elem.tag if isinstance(tag, QName): if tag.text not in qnames: @@ -933,7 +940,7 @@ text = elem.text if isinstance(text, QName) and text.text not in qnames: add_qname(text.text) - return qnames, namespaces + return qnames def _serialize_xml(write, elem, qnames, namespaces): tag = elem.tag @@ -1152,13 +1159,13 @@ # @return An (optionally) encoded string containing the XML data. # @defreturn string -def tostring(element, encoding=None, method=None): +def tostring(element, encoding=None, method=None, **kw): class dummy: pass data = [] file = dummy() file.write = data.append - ElementTree(element).write(file, encoding, method=method) + ElementTree(element).write(file, encoding, method=method, **kw) if encoding in (str, "unicode"): return "".join(data) else: @@ -1179,13 +1186,13 @@ # @defreturn sequence # @since 1.3 -def tostringlist(element, encoding=None, method=None): +def tostringlist(element, encoding=None, method=None, **kw): class dummy: pass data = [] file = dummy() file.write = data.append - ElementTree(element).write(file, encoding, method=method) + ElementTree(element).write(file, encoding, method=method, **kw) # FIXME: merge small fragments into larger parts return data