Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 545
MartyMacGyver Avatar asked Jun 13 '13 10:06

MartyMacGyver


People also ask

Can XML have multiple namespaces?

When you use multiple namespaces in an XML document, you can define one namespace as the default namespace to create a cleaner looking document. The default namespace is declared in the root element and applies to all unqualified elements in the document. Default namespaces apply to elements only, not to attributes.

What is XML Etree ElementTree in Python?

The xml. etree. ElementTree module implements a simple and efficient API for parsing and creating XML data. Changed in version 3.3: This module will use a fast implementation whenever available.

What is XML schema namespace?

As defined by the W3C Namespaces in XML Recommendation , an XML namespace is a collection of XML elements and attributes identified by an Internationalized Resource Identifier (IRI); this collection is often referred to as an XML "vocabulary."


2 Answers

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.

like image 88
jfs Avatar answered Nov 12 '22 16:11

jfs


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')
like image 32
Sergey Grushko Avatar answered Nov 12 '22 16:11

Sergey Grushko