Alter namespace prefixing with ElementTree in Python

Gabriel Hurley picture Gabriel Hurley · Aug 8, 2009 · Viewed 9.8k times · Source

By default, when you call ElementTree.parse(someXMLfile) the Python ElementTree library prefixes every parsed node with it's namespace URI in Clark's Notation:

    {http://example.org/namespace/spec}mynode

This makes accessing specific nodes by name a huge pain later in the code.

I've read through the docs on ElementTree and namespaces and it looks like the iterparse() function should allow me to alter the way the parser prefixes namespaces, but for the life of me I can't actually make it change the prefix. It seems like that may happen in the background before the ns-start event even fires as in this example:

for event, elem in iterparse(source):
    if event == "start-ns":
        namespaces.append(elem)
    elif event == "end-ns":
        namespaces.pop()
    else:
        ...

How do I make it change the prefixing behavior and what is the proper thing to return when the function ends?

Answer

Vinay Sajip picture Vinay Sajip · Aug 10, 2009

You don't specifically need to use iterparse. Instead, the following script:

from cStringIO import StringIO
import xml.etree.ElementTree as ET

NS_MAP = {
    'http://www.red-dove.com/ns/abc' : 'rdc',
    'http://www.adobe.com/2006/mxml' : 'mx',
    'http://www.red-dove.com/ns/def' : 'oth',
}

DATA = '''<?xml version="1.0" encoding="utf-8"?>
<rdc:container xmlns:mx="http://www.adobe.com/2006/mxml"
                 xmlns:rdc="http://www.red-dove.com/ns/abc"
                 xmlns:oth="http://www.red-dove.com/ns/def">
  <mx:Style>
    <oth:style1/>
  </mx:Style>
  <mx:Style>
    <oth:style2/>
  </mx:Style>
  <mx:Style>
    <oth:style3/>
  </mx:Style>
</rdc:container>'''

tree = ET.parse(StringIO(DATA))
some_node = tree.getroot().getchildren()[1]
print ET.fixtag(some_node.tag, NS_MAP)
some_node = some_node.getchildren()[0]
print ET.fixtag(some_node.tag, NS_MAP)

produces

('mx:Style', None)
('oth:style2', None)

Which shows how you can access the fully-qualified tag names of individual nodes in a parsed tree. You should be able to adapt this to your specific needs.