27

Is there a way to define the default/unprefixed namespace in python ElementTree? This doesn't seem to work...

ns = {"":"http://maven.apache.org/POM/4.0.0"}
pom = xml.etree.ElementTree.parse("pom.xml")
print(pom.findall("version", ns))

Nor does this:

ns = {None:"http://maven.apache.org/POM/4.0.0"}
pom = xml.etree.ElementTree.parse("pom.xml")
print(pom.findall("version", ns))

This does, but then I have to prefix every element:

ns = {"mvn":"http://maven.apache.org/POM/4.0.0"}
pom = xml.etree.ElementTree.parse("pom.xml")
print(pom.findall("mvn:version", ns))

Using Python 3.5 on OSX.

EDIT: if the answer is "no", you can still get the bounty :-). I just want a definitive "no" from someone who's spent a lot of time using it.

Stevoisiak
  • 23,794
  • 27
  • 122
  • 225
Robert Fraser
  • 10,649
  • 8
  • 69
  • 93
  • Using `ElementTree`, you have to use a prefix. If you use `lxml`, you can use `.nsmap` instead of hard-coding prefixes. See http://stackoverflow.com/questions/14853243/parsing-xml-with-namespace-in-python-via-elementtree for details – gtlambert Feb 02 '16 at 23:44

3 Answers3

29

NOTE: for Python 3.8+ please see this answer.


There is no straight-forward way to handle the default namespaces transparently. Assigning the empty namespace a non-empty name is a common solution, as you've already mentioned:

ns = {"mvn":"http://maven.apache.org/POM/4.0.0"}
pom = xml.etree.ElementTree.parse("pom.xml")
print(pom.findall("mvn:version", ns))

Note that lxml.etree does not allow the use of empty namespaces explicitly. You would get:

ValueError: empty namespace prefix is not supported in ElementPath


You can though, make things simpler, by removing the default namespace definition while loading the XML input data:

import xml.etree.ElementTree as ET
import re
 
with open("pom.xml") as f:
    xmlstring = f.read()
 
# Remove the default namespace definition (xmlns="http://some/namespace")
xmlstring = re.sub(r'\sxmlns="[^"]+"', '', xmlstring, count=1)
 
pom = ET.fromstring(xmlstring) 
print(pom.findall("version"))
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
11

ElementTree in Python 3.8 allows empty string as a prefix, so you can declare:

ns = {'': 'http://maven.apache.org/POM/4.0.0'}

and use that as the second arg in the find* methods.

Source: https://docs.python.org/3.8/library/xml.etree.elementtree.html?highlight=xml#xml.etree.ElementTree.Element.find

delocalizer
  • 398
  • 3
  • 11
2

You can retrieve the default namespace with:

namespace = pom.getroot().tag.split("}")[0]+"}"

Then when you search for elements you add it to your search path:

print(pom.findall(namespace+"version"))

Not an elegant solution, but it works.

Peppe L-G
  • 7,351
  • 2
  • 25
  • 50