bonzi
bonzi

Reputation: 359

Remove elements with text using lxml

I have the following xml file

<xml>
  <network id="5">
    <nodelist>
      <IP>10.10.0.135::3111</IP>
      <IP>10.10.0.130::3111</IP>
      <IP>10.10.0.129::3111</IP>
      <IP>10.10.0.129::3111</IP>
    </nodelist>
    <nodelist2/>
  </network>
</xml>

I want to remove all the elements with IP 10.10.0.129 where network id=5. How can I do it in lxml?

Currently, I'm trying to find the nodes using xpath and I'm trying to remove it.

But,

netid=xml.xpath("network[@id=%s]/nodelist/IP[contains(text(),%s)]"%(id,node))

Gives me error lxml.etree.XPathEvalError: Invalid expression.

Upvotes: 3

Views: 2352

Answers (3)

Alan Hynes
Alan Hynes

Reputation: 236

Using lxml under Python2.7:

tree = ET.fromstring(xml_fragment) ## Or tree = ET.parse(somefile)

for rn in tree.xpath('network[@id="5"]//IP[starts-with(text(),"10.10.0.129:")]'):
    rn.getparent().remove(rn)

Upvotes: 0

AI Generated Response
AI Generated Response

Reputation: 8837

I'm a python programmer, so I have it coded in python 2.7. If you need to use a different language, you will have to port it yourself since I don't do anything but Python.

Note, although this seemingly deals with xpath, most of my processing is done with python.

import lxml.etree as etree  #import etree, like c's include

def delete(xml,networkid,ipaddr):
    tree = etree.fromstring(xml)
    networks = tree.findall('.//network[@id="%s"]'%str(networkid)) #I think you forgot the quotes in your insertion.  
    for network in networks:  #for each network that has id='5'.
        ips = network.findall('.//IP') #All the IP elements under the network
        for ip in ips:  #iterating through a list of ips
            if ipaddr in ip.text:  #if ipaddr is inside the text, even if a port is appended
                ip.getparent().remove(ip)  #the ip's parent (nodelist) removes the ip element
return tree  # I give you the tree


s = r'''<xml>  #Here's your original xml
  <network id="5">
    <nodelist>
      <IP>10.10.0.135::3111</IP>
      <IP>10.10.0.130::3111</IP>
      <IP>10.10.0.129::3111</IP>
      <IP>10.10.0.129::3111</IP>
    </nodelist>
    <nodelist2/>
  </network>
</xml>'''

res = delete(s,'5','10.10.0.129')  #here's the result
print res  #and it's a tree.
print list(res.iter())  #so I print all the items under it.
print etree.tostring(res)  #and you have your edited xml.

Upvotes: 5

AI Generated Response
AI Generated Response

Reputation: 8837

This should be it.

tree.xpath(r'''network[@id="%s"]/nodelist/IP[not(contains(text(),"%s"))]'''%('5','10.10.0.129'))

Where the stuff between the triple-single-quotes is your xpath code (I tested with python so I have to). This gives you all the IP elements with your specifications. Apparently python's lxml.etree.xml.xpath won't let me remove, but this will give you everything else.

Upvotes: 0

Related Questions