Having all namespace declarations in the root element

Hi, I made an XML doc grabbing and assembling nodes from various stuffs. namespace declarations are consistent but repeated among various descendant elements. And I want to gather all these namespace declarations in the root element. i. e. when I have : <root> <foo xmlns:abc="abc.namespace"> <abc:bar attrib="value"> blah </abc:bar> </foo> <joe xmlns:abc="abc.namespace"> <abc:stuff> stuff </abc:stuff> </joe> </root> Then I need (once serialized with .tostring(...) : <root xmlns:abc="abc.namespace"> <foo> <abc:bar attrib="value"> blah </abc:bar> </foo> <joe> <abc:stuff> stuff </abc:stuff> </joe> </root> I naively thought that merging all elements .nsmap attribs into the root.nsmap should do the job, but it appears that changes to the Element.nsmap mapping fail silently. My code (what I want to do with a really mutable .nsmap) : ---- etree.cleanup_namespaces(doc) for elem in doc.getiterator(): if hasattr(elem, 'nsmap'): for k in elem.nsmap: doc.nsmap[k] = elem.nsmap.pop(k) ---- Unfortunately .nsmap attrib is a so called "non mutable dict but ignoring silently mutation attempts". Thus this code does not work as expected. Any hint to unlock me is welcome. Best regards -- Gilles Lenfant

Am .02.2015, 14:59 Uhr, schrieb Gilles Lenfant <gilles.lenfant@gmail.com>:
I think this happens to us all at some point. What you need to do is use the nsmap argument when creating your root element and pass it in a dictionary of (prefix, namespace). Charlie -- Charlie Clark Managing Director Clark Consulting & Research German Office Kronenstr. 27a Düsseldorf D- 40217 Tel: +49-211-600-3657 Mobile: +49-178-782-6226

2015-02-12 15:07 GMT+01:00 Charlie Clark <charlie.clark@clark-consulting.eu> :
Many thanks Charlie for that fast and efficient hint, For those who will search for the solution in the ML archive, here it is : -------- etree.cleanup_namespaces(doc) global_nsmap = {} for elem in doc.getiterator(): if hasattr(elem, 'nsmap'): global_nsmap.update(elem.nsmap) new_doc = etree.Element(doc.tag, nsmap=global_nsmap) for elem in doc: new_doc.append(elem) etree.cleanup_namespaces(new_doc) --------

Charlie Clark schrieb am 12.02.2015 um 15:07:
Would it help if the ElementMaker (a.k.a. E-factory) aggregated the namespace declarations of the children it receives? I don't think this is worth changing the way Elements work overall, but changing the ElementMaker sounds doable and reasonable to me. Stefan

Did the OP actually use the E-factory for tree assembly? Or you probably mean one should then use it to combine nodes to assemble, if aggregation is desired. Maybe a convenience helper like cleanup_namespaces(...) could be useful? Or a switch to make cleanup_namespaces optionally propagate namespace declarations "upwards" in the tree, if possible (i.e. there's no remapping of the prefix). Holger Landesbank Baden-Wuerttemberg Anstalt des oeffentlichen Rechts Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz HRA 12704 Amtsgericht Stuttgart

Holger Joukl schrieb am 13.02.2015 um 10:38:
Yes. Although I guess that most data would already be passed through cleanup_namespaces() anyway when this comes up as an issue, so that might be the 'cleaner' canonical solution.
The latter, I think, maybe as an explicit nsmap that declares the namespaces on the Element that was passed in, iff they are used in the tree. Patches welcome. Stefan

Stefan Behnel schrieb am 13.02.2015 um 10:58:
Have fun: https://github.com/lxml/lxml/commit/4a1c2e9ff3c99247ec1da2707b29e3bb336d641d Stefan

Am .02.2015, 14:59 Uhr, schrieb Gilles Lenfant <gilles.lenfant@gmail.com>:
I think this happens to us all at some point. What you need to do is use the nsmap argument when creating your root element and pass it in a dictionary of (prefix, namespace). Charlie -- Charlie Clark Managing Director Clark Consulting & Research German Office Kronenstr. 27a Düsseldorf D- 40217 Tel: +49-211-600-3657 Mobile: +49-178-782-6226

2015-02-12 15:07 GMT+01:00 Charlie Clark <charlie.clark@clark-consulting.eu> :
Many thanks Charlie for that fast and efficient hint, For those who will search for the solution in the ML archive, here it is : -------- etree.cleanup_namespaces(doc) global_nsmap = {} for elem in doc.getiterator(): if hasattr(elem, 'nsmap'): global_nsmap.update(elem.nsmap) new_doc = etree.Element(doc.tag, nsmap=global_nsmap) for elem in doc: new_doc.append(elem) etree.cleanup_namespaces(new_doc) --------

Charlie Clark schrieb am 12.02.2015 um 15:07:
Would it help if the ElementMaker (a.k.a. E-factory) aggregated the namespace declarations of the children it receives? I don't think this is worth changing the way Elements work overall, but changing the ElementMaker sounds doable and reasonable to me. Stefan

Did the OP actually use the E-factory for tree assembly? Or you probably mean one should then use it to combine nodes to assemble, if aggregation is desired. Maybe a convenience helper like cleanup_namespaces(...) could be useful? Or a switch to make cleanup_namespaces optionally propagate namespace declarations "upwards" in the tree, if possible (i.e. there's no remapping of the prefix). Holger Landesbank Baden-Wuerttemberg Anstalt des oeffentlichen Rechts Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz HRA 12704 Amtsgericht Stuttgart

Holger Joukl schrieb am 13.02.2015 um 10:38:
Yes. Although I guess that most data would already be passed through cleanup_namespaces() anyway when this comes up as an issue, so that might be the 'cleaner' canonical solution.
The latter, I think, maybe as an explicit nsmap that declares the namespaces on the Element that was passed in, iff they are used in the tree. Patches welcome. Stefan

Stefan Behnel schrieb am 13.02.2015 um 10:58:
Have fun: https://github.com/lxml/lxml/commit/4a1c2e9ff3c99247ec1da2707b29e3bb336d641d Stefan
participants (4)
-
Charlie Clark
-
Gilles Lenfant
-
Holger Joukl
-
Stefan Behnel