More compact ElementTree or lxml namespaces

I am trying to get a compact representation of namespaces in ElementTree or lxml when subitems are in another namespace as a parent. Here is a basic example:

from lxml import etree

country = etree.Element("country")

name = etree.SubElement(country, "{urn:test}name")
name.text = "Canada"
population = etree.SubElement(country, "{urn:test}population")
population.text = "34M"
etree.register_namespace('tst', 'urn:test')

print( etree.tostring(country, pretty_print=True) )

I also tried this approach:

ns = {"test" : "urn:test"}

country = etree.Element("country", nsmap=ns)

name = etree.SubElement(country, "{test}name")
name.text = "Canada"
population = etree.SubElement(country, "{test}population")
population.text = "34M"

print( etree.tostring(country, pretty_print=True) )

In both cases, I get something like this:

<country>
    <ns0:name xmlns:ns0="urn:test">Canada</ns0:name>
    <ns1:population xmlns:ns1="urn:test">34M</ns1:population>
</country>

Although this is correct, I would like it to be less verbose - it could be a real problem with large datasets (and especially because I use a much larger NS than urn: test).

If I agree that the "country" is inside the "urn: test" namespace and declares it like this (in the first example above):

country = etree.Element("{test}country")

then I get the following output:

<ns0:country xmlns:ns0="urn:test">
    <ns0:name>Canada</ns0:name>
    <ns0:population>34M</ns0:population>
</ns0:country>

But I really want this:

<country xmlns:ns0="urn:test">
    <ns0:name>Canada</ns0:name>
    <ns0:population>34M</ns0:population>
<country>

Any ideas?

+5
source
3
from xml.etree import cElementTree as ET
##ET.register_namespace('tst', 'urn:test')
country = ET.Element("country")
name = ET.SubElement(country, "{urn:test}name")
name.text = "Canada"
population = ET.SubElement(country, "{urn:test}population")
population.text = "34M"
print prettify(country)

( - ):

<?xml version="1.0" ?>
<country xmlns:ns0="urn:test">
  <ns0:name>Canada</ns0:name>
  <ns0:population>34M</ns0:population>
</country>

, , ::

<?xml version="1.0" ?>
<country xmlns:tst="urn:test">
  <tst:name>Canada</tst:name>
  <tst:population>34M</tst:population>
</country>

: prettify

+1
  • {namespace-url}elementName, {prefix}elementName

    >>> from lxml import etree as ET
    >>> r = ET.Element('root', nsmap={'tst': 'urn:test'})
    >>> ET.SubElement(r, "{urn:test}child")
    <Element {urn:test}child at 0x2592a80>
    >>> ET.tostring(r)
    '<root xmlns:tst="urn:test"><tst:child/></root>'
    
  • , . , lxml, -, XML, , , dafault , :

    >>> r = ET.Element('{urn:test}root', nsmap={None: 'urn:test'})
    >>> ET.SubElement(r, "{urn:test}child")
    <Element {urn:test}child at 0x2592b20>
    >>> ET.SubElement(r, "{urn:test}child")
    <Element {urn:test}child at 0x25928f0>
    >>> ET.tostring(r)
    '<root xmlns="urn:test"><child/><child/></root>'
    
+2

This code:

from lxml import etree

ns = {"ns0" : "urn:test"}
country = etree.Element("country", nsmap=ns)

name = etree.SubElement(country, "{urn:test}name")
name.text = "Canada"

population = etree.SubElement(country, "{urn:test}population")
population.text = "34M"

print(etree.tostring(country, pretty_print=True))

seems to provide the required output:

<country xmlns:ns0="urn:test">
  <ns0:name>Canada</ns0:name>
  <ns0:population>34M</ns0:population>
</country>

but you still need to support nsmapyourself.

+1
source

All Articles