Python 2.7 and xml.etree: how to create an XML file with multiple namespaces?
Asked Answered
M

2

5

I'm trying to create an XML file so that it has the following skeleton, preferably using the xml.etree modules in Python 2.7:

<?xml version="1.0"?>
<foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" thing1="this" thing2="that">
  ....
  <somedata bar="1">
    <moredata whatsit="42"></moredata>
  </somedata>
  ....
</foo>

It's the "foo ...." line that vexes me. I tried using nsmap for bringing in xsi and xsd, but that led to a "cannot serialize" error.

I could construct or otherwise hack that line's text to be exactly as I want it, but I'd like to learn to do this programmatically using xml.etree (pulling in an external library is not preferable in this situation).

I'd think this is a common pattern but I'm just not finding it anywhere for Python and etree.

Motionless answered 13/6, 2013 at 10:0 Comment(2)
I tried to do something similar once, unfortunately it seems xml.etree is too weak for that.Alkalosis
Is it possible that all that "xmlns:xsi" and "xmlns:xsd" business is simply superfluous, since "thing1" and "thing2" do not have any namespace attached to them anyway? I'm just worried that I'd be oversimplifying this for one case and missing a chance to learn to do it properly (other cases might have more stringent requirements).Motionless
L
6

If the prefixes are used in the document; you could call register_namespace() to add them:

import sys
import xml.etree.ElementTree as etree

xsi =  "http://www.w3.org/2001/XMLSchema-instance"
xsd =  "http://www.w3.org/2001/XMLSchema"
ns = {"xmlns:xsi": xsi, "xmlns:xsd": xsd}
for attr, uri in ns.items():
    etree.register_namespace(attr.split(":")[1], uri)

foo = etree.Element("foo",
    dict(thing1="this", thing2="that")) # put `**ns))` if xsi, xsd are unused
somedata = etree.SubElement(foo, "somedata", dict(bar="1"))
etree.SubElement(somedata, "moredata",
    {"whatsit": "42", etree.QName(xsi, "type"): etree.QName(xsd, "string")})

etree.ElementTree(foo).write(sys.stdout, xml_declaration=True)

Otherwise, you could set the attributes explicitly (ns dict) if you need it.

Literature answered 13/6, 2013 at 12:21 Comment(1)
That seems to work (I'm not quite sure I need the "xsi:type="xsd:string"" bit in the moredata output, but at least this shows how to get the namespaces set correctly). Thank you! Upvote in kind if you think my question and your answer would help others (I think it would).Motionless
Y
2
import xml.etree.ElementTree as et

foo = et.Element('foo', **{'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance'}, **{'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema'})
somedata = et.SubElement(foo, 'somedata', bar='1')
moredata = et.SubElement(somedata, 'moredata', whatsit='42')
tree = et.ElementTree(foo)
tree.write('file.xml')
Yale answered 24/12, 2018 at 18:1 Comment(1)
While this code snippet may be the solution, including an explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion.Avast

© 2022 - 2024 — McMap. All rights reserved.