I am trying to parse an xml file using lxml.
my_tree = etree.parse(file)
my_root = my_tree.getroot()
for child in my_root:
print(child.tag)
# {some default namespace}Prop
# {some default namespace}Prop
# {some default namespace}Stuff
# ...
Ideally, I just want to get all the elements I want with something like
my_root.findall('Prop', my_root.nsmap)
but this is returning an empty list. I noticed that the my_root.nsmap dictionary had a None item with the default namespace.
nsmap = {None: 'default namespace', ...}
I found a quick workaround by copying the nsmap and adding a 'default' item with the same value as the None item, and then I do
my_root.findall('default:Prop', new_map)
This feels very hackish. Why is None even in the namespace map? Is there some straightforward method in lxml the automatically uses the default namespace?
Edit: The xml I am looking at is along the lines of
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ScenarioProps xmlns="http://filler.com/default.xsd" xmlns:ns2="http://filler.com/ns.xsd" id="Test">
<Prop id="Wi-Fi">
<ns2:Position x="0.0" y="0.0" z="0.0"/>
<ns2:Orientation roll="0.0" pitch="0.0" yaw="0.0"/>
</Prop>
</ScenarioProps>
Hackish or not, you have to specify a prefix. XPath 1.0, which is what lxml supports, does not have a concept of default namespace (it works differently in XPath 2.0, but that does not apply here).
The other option is to not bother with prefixes at all. Use the fully qualified element name in "Clark notation" instead:
my_root.findall('{http://filler.com/default.xsd}Prop').
See also http://lxml.de/FAQ.html#how-can-i-specify-a-default-namespace-for-xpath-expressions.
The behaviour has changed in later versions of lxml. With lxml 4.4.1, both None and the empty string can be used:
from lxml import etree
my_tree = etree.parse("props.xml")
my_root = my_tree.getroot()
NS = 'http://filler.com/default.xsd'
NSMAP1 = {None: NS}
NSMAP2 = {'': NS}
NSMAP3 = {'default': NS}
print(my_root.findall('Prop', NSMAP1))
print(my_root.findall('Prop', NSMAP2))
print(my_root.findall('default:Prop', NSMAP3))
Output:
[<Element {http://filler.com/default.xsd}Prop at 0x31f1260>]
[<Element {http://filler.com/default.xsd}Prop at 0x31f1288>]
[<Element {http://filler.com/default.xsd}Prop at 0x31f1260>]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With