Search code examples
pythonxmlxml-serializationelementtree

Suppressing namespace prefixes in ElementTree 1.2


In python 2.7 (with etree 1.3), I can suppress the XML prefixes on elements like this:

Python 2.7.1 (r271:86832, Jun 16 2011, 16:59:05) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import xml.etree.ElementTree as etree
>>> etree.VERSION
'1.3.0'
>>> something = etree.Element('{http://some.namespace}token')
>>> etree.tostring(something)
'<ns0:token xmlns:ns0="http://some.namespace" />'
>>> etree.register_namespace('', 'http://some.namespace')
>>> etree.tostring(something)
'<token xmlns="http://some.namespace" />'

The register_namespace function was added in 1.3. I'm trying to remove the prefix in a way that is compatible with python 2.6's etree at version 1.2.6. Here's what I've tried:

Python 2.6.7 (r267:88850, Jul 31 2011, 19:30:54) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import xml.etree.ElementTree as etree
>>> etree.VERSION
'1.2.6'
>>> something = etree.Element('{http://some.namespace}token')
>>> etree.tostring(something)
'<ns0:token xmlns:ns0="http://some.namespace" />'
>>> etree._namespace_map['http://some.namespace'] = ''
>>> etree.tostring(something)
'<:token xmlns:="http://some.namespace" />'

This is not what I want. The prefixes are still there but are blank. Is there any way to remove them completely?


Solution

  • After looking at the source code for ElementTree in python2.6, the : is hard coded in the fixtag function. As a workaround, here's what I did:

    from xml.etree import ElementTree as etree
    
    if etree.VERSION[0:3] == '1.2':
        #in etree < 1.3, this is a workaround for supressing prefixes
    
        def fixtag(tag, namespaces):
            import string
            # given a decorated tag (of the form {uri}tag), return prefixed
            # tag and namespace declaration, if any
            if isinstance(tag, etree.QName):
                tag = tag.text
            namespace_uri, tag = string.split(tag[1:], "}", 1)
            prefix = namespaces.get(namespace_uri)
            if namespace_uri not in namespaces:
                prefix = etree._namespace_map.get(namespace_uri)
                if namespace_uri not in etree._namespace_map:
                    prefix = "ns%d" % len(namespaces)
                namespaces[namespace_uri] = prefix
                if prefix == "xml":
                    xmlns = None
                else:
                    if prefix is not None:
                        nsprefix = ':' + prefix
                    else:
                        nsprefix = ''
                    xmlns = ("xmlns%s" % nsprefix, namespace_uri)
            else:
                xmlns = None
            if prefix is not None:
                prefix += ":"
            else:
                prefix = ''
    
            return "%s%s" % (prefix, tag), xmlns
    
        etree.fixtag = fixtag
        etree._namespace_map['http://some.namespace'] = None
    else:
        #For etree > 1.3, use register_namespace function
        etree.register_namespace('', 'http://some.namespace')
    

    In case this post ever gets out of date, the code is maintained here.