Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

lxml - Default name spaces

Tags:

python

xml

lxml

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>
like image 738
Shatnerz Avatar asked Sep 05 '26 13:09

Shatnerz


1 Answers

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.

Update August 2019

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>]
like image 175
mzjn Avatar answered Sep 07 '26 04:09

mzjn



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!