Having all namespace declarations in the root element
![](https://secure.gravatar.com/avatar/e2df9186d6b4ace31885f66e4b31a339.jpg?s=120&d=mm&r=g)
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
![](https://secure.gravatar.com/avatar/3a93c5a0f975385738c1f27848f3b50a.jpg?s=120&d=mm&r=g)
Am .02.2015, 14:59 Uhr, schrieb Gilles Lenfant <gilles.lenfant@gmail.com>:
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.
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
![](https://secure.gravatar.com/avatar/e2df9186d6b4ace31885f66e4b31a339.jpg?s=120&d=mm&r=g)
2015-02-12 15:07 GMT+01:00 Charlie Clark <charlie.clark@clark-consulting.eu> :
Am .02.2015, 14:59 Uhr, schrieb Gilles Lenfant <gilles.lenfant@gmail.com>:
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.
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 _________________________________________________________________
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) --------
![](https://secure.gravatar.com/avatar/8b97b5aad24c30e4a1357b38cc39aeaa.jpg?s=120&d=mm&r=g)
Charlie Clark schrieb am 12.02.2015 um 15:07:
Am .02.2015, 14:59 Uhr, schrieb Gilles Lenfant:
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.
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).
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
![](https://secure.gravatar.com/avatar/bc4259003fffe3e1cb3543db975bea0d.jpg?s=120&d=mm&r=g)
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>
[...] 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.
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
![](https://secure.gravatar.com/avatar/8b97b5aad24c30e4a1357b38cc39aeaa.jpg?s=120&d=mm&r=g)
Holger Joukl schrieb am 13.02.2015 um 10:38:
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.
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.
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.
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).
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
![](https://secure.gravatar.com/avatar/8b97b5aad24c30e4a1357b38cc39aeaa.jpg?s=120&d=mm&r=g)
Stefan Behnel schrieb am 13.02.2015 um 10:58:
Holger Joukl schrieb am 13.02.2015 um 10:38:
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.
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.
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.
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).
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.
Have fun: https://github.com/lxml/lxml/commit/4a1c2e9ff3c99247ec1da2707b29e3bb336d641d Stefan
participants (4)
-
Charlie Clark
-
Gilles Lenfant
-
Holger Joukl
-
Stefan Behnel