yin_bill_wang
yin_bill_wang

Reputation: 21

Using xpath with lxml.etree._ElementTree

I have an object arptree, I am trying to locate the mac-address of an ip-address, but failed.

>>> arptree 
<lxml.etree._ElementTree object at 0x0000000004641688>

When I try the following xpath, it returns an empty list

>>> arptree.xpath("descendant::mac-address[following-sibling::ip-address='10.69.119.150']")
[]

If I modify the xpath to exclude "='10.69.119.150'", it actually returns a list of Elements.

>>> arptree.xpath("descendant::mac-address[following-sibling::ip-address]")                      

[, , , , , , , , , ]

I can use a for loop to access the content. And I am sure the mac-address for ip-address 10.69.119.150 is there.

for elt in arptree.iter():
    print elt.tag, elt.text

The strange thing is that if I copy and paste the xml output to a xml file. Then use:

from lxml import etree
tree = etree.parse(open('arp.xml'))
tree.xpath("descendant::mac-address[following-sibling::ip-address='10.69.119.150']")

It will return the mac-address for the ip address.

I'm using Python 2.7.9 with lxml package. Can anyone help?

Update 1: example XML

<arp-table-information>
<arp-table-entry>
    <mac-address>00:a0:a5:76:1a:96</mac-address>
    <ip-address>10.69.119.130</ip-address>
    <hostname>10.69.119.130</hostname>
    <interface-name>vlan.49</interface-name>
    <arp-table-entry-flags>
        <none/>
    </arp-table-entry-flags>
</arp-table-entry>
<arp-table-entry>
    <mac-address>00:0f:bb:c6:26:3d</mac-address>
    <ip-address>10.69.119.150</ip-address>
    <hostname>10.69.119.150</hostname>
    <interface-name>vlan.55</interface-name>
    <arp-table-entry-flags>
        <none/>
    </arp-table-entry-flags>
</arp-table-entry>
</arp-table-information>

Update 2: Please ignore Update 1

When I use

arptree = ex.device.rpc.get_arp_table_information().getroottree()
arptree.write('arptree.xml', pretty_print=True)

to save the ElementTree to a xml, the layout changes to

<arp-table-information style="normal">
<arp-table-entry>
<mac-address>
00:a0:a5:76:1a:96
</mac-address>
<ip-address>
10.69.119.130
</ip-address>
<hostname>
10.69.119.130
</hostname>
<interface-name>
vlan.49
</interface-name>
<arp-table-entry-flags>
<none/>
</arp-table-entry-flags>
</arp-table-entry>
<arp-table-entry>
<mac-address>
00:0f:bb:c6:26:3d
</mac-address>
<ip-address>
10.69.119.150
</ip-address>
<hostname>
10.69.119.150
</hostname>
<interface-name>
vlan.55
</interface-name>
<arp-table-entry-flags>
<none/>
</arp-table-entry-flags>
</arp-table-entry>

Maybe this is why the following code doesn't work???

arptree.xpath("descendant::mac-address[following-sibling::ip-address='10.69.119.150']")

Based on this xml file, can anyone help?

Upvotes: 2

Views: 1031

Answers (1)

har07
har07

Reputation: 89285

In the 2nd XML, you have new line characters before and after the IP address value. You can use normalize-space() function to fix it :

descendant::mac-address[following-sibling::ip-address[normalize-space()='10.69.119.150']]

working example for demo :

from lxml import etree

xml = """<arp-table-information style="normal">
<arp-table-entry>
<mac-address>
00:a0:a5:76:1a:96
</mac-address>
<ip-address>
10.69.119.130
</ip-address>
<hostname>
10.69.119.130
</hostname>
<interface-name>
vlan.49
</interface-name>
<arp-table-entry-flags>
<none/>
</arp-table-entry-flags>
</arp-table-entry>
<arp-table-entry>
<mac-address>
00:0f:bb:c6:26:3d
</mac-address>
<ip-address>
10.69.119.150
</ip-address>
<hostname>
10.69.119.150
</hostname>
<interface-name>
vlan.55
</interface-name>
<arp-table-entry-flags>
<none/>
</arp-table-entry-flags>
</arp-table-entry>
</arp-table-information>"""

root = etree.fromstring(xml)
result = root.xpath("descendant::mac-address[following-sibling::ip-address[normalize-space()='10.69.119.150']]")
for r in result:
    print(etree.tostring(r))

output :

<mac-address>
00:0f:bb:c6:26:3d
</mac-address>

Upvotes: 2

Related Questions