5

I'm working with some of google's data APIs, using the lxml library in python. Namespaces are a huge hassle here. For a lot of the work I'm doing (xpath stuff, mainly), it would be nice to just plain ignore them.

Is there a simple way to ignore xml namespaces in python/lxml?

thanks!

Abe
  • 22,738
  • 26
  • 82
  • 111
  • 3
    related: [remove namespaces via an XSL transformation](http://stackoverflow.com/a/4256126/4279) – jfs Feb 16 '12 at 20:01
  • see also: [Python ElementTree module: How to ignore the namespace of XML files](https://stackoverflow.com/questions/13412496/python-elementtree-module-how-to-ignore-the-namespace-of-xml-files-to-locate-ma/76601149#76601149) – milahu Jul 03 '23 at 06:50

2 Answers2

1

If you'd like to remove all namespaces from elements and attributes, I suggest the code shown below.

Context: In my application I'm obtaining XML representations of SOAP response streams, but I'm not interested on building objects on the client side; I'm only interested on XML representations themselves. Moreover, I'm not interested on any namespace thing, which only makes things more complicated than they need to be, for my purposes. So, I simply remove namespaces from elements and I drop all attributes which contain namespaces.

def dropns(root):
    for elem in root.iter():
        parts = elem.tag.split(':')
        if len(parts) > 1:
            elem.tag = parts[-1]
        entries = []
        for attrib in elem.attrib:
            if attrib.find(':') > -1:
                entries.append(attrib)
        for entry in entries:
            del elem.attrib[entry]

# Test case
name = '~/tmp/mantisbt/test.xml'
f = open(name, 'rb')
import lxml.etree as etree
parser = etree.XMLParser(ns_clean=True, recover=True)
root = etree.parse(f, parser=parser)
print('=====================================================================')
print etree.tostring(root, pretty_print = True)
print('=====================================================================')
dropns(root)
print etree.tostring(root, pretty_print = True)
print('=====================================================================')

which prints:

=====================================================================
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <ns1:mc_issue_getResponse>
      <return xsi:type="tns:IssueData">
        <id xsi:type="xsd:integer">356</id>
        <view_state xsi:type="tns:ObjectRef">
          <id xsi:type="xsd:integer">10</id>
          <name xsi:type="xsd:string">public</name>
        </view_state>
    </return>
  </ns1:mc_issue_getResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
=====================================================================
<Envelope>
  <Body>
    <mc_issue_getResponse>
      <return>
        <id>356</id>
        <view_state>
          <id>10</id>
          <name>public</name>
        </view_state>
    </return>
  </mc_issue_getResponse>
</Body>
</Envelope>
=====================================================================
Richard Gomes
  • 5,675
  • 2
  • 44
  • 50
-2

In lxml some_element.tag is a string like {namespace-uri}local-name if there is a namespace, just local-name otherwise. Beware that it is a non string value on non-element nodes (such as comments).

Try this:

for node in some_tree.iter():
    startswith = getattr(node 'startswith', None)
    if startswith and startswith('{'):
        node.tag = node.tag.rsplit('}', 1)[-1]

On Python 2.x the tag can be either an ASCII byte-string or an Unicode string. The existence of a startswith method tests for either.

Simon Sapin
  • 9,790
  • 3
  • 35
  • 44