Delete specific element from xml file with multiple occurrence using python

Viewed 100

Hi Stackoverflow Community,

I would appreciate some guidance in adjusting my XML file with Python and the elementTree library.

for now I have the following file.xml:

<component xmlns:xsi="http://www.w3.orgr">
  <memoryMaps>
    <memoryMap>
      <name>name</name>
      <description>description</description>
      <peripheral>
        <name>periph</name>
        <description>description</description>
        <baseAddress>0x0</baseAddress>
        <range>0x8</range>
        <width>32</width>
       <registers>
        <register>
          <name>reg1</name>
          <displayName>reg1</displayName>
          <description>This is register 1</description>
          <addressOffset>0x0</addressOffset>
          <size>32</size>
          <access>read-write</access>
          <resetValue>0x00000002</resetValue>
          <resetMask>0xFFFFFFFF</resetMask>
         <fields>
           .................
         </fields>
         <resetValue>0x00000002</resetValue>
         <resetMask>0xFFFFFFFF</resetMask>
         <description>This is register 1</description>
        </register>                           
        <register>
          <name>reg2</name>
          <displayName>reg2</displayName>
          <description>This is register 2</description>
          <addressOffset>0x0</addressOffset>
          <size>32</size>
          <access>read-write</access>
          <resetValue>0x00000000</resetValue>
          <resetMask>0xFFFFFFFF</resetMask>
         <fields>
           .................
         </fields>
         <resetValue>0x00000000</resetValue>
         <resetMask>0xFFFFFFFF</resetMask>
         <description>This is register 2</description>
         </register>
         <register>
             ..................
         </register>  
       </registers>    
      </peripheral>
    </memoryMap>
  </memoryMaps>
</component>

As you see in the end of each 'register' I have 3 elements: 'resetValue' , 'resetMask' and 'description' that also exist in other places before in 'register', but I want to delete the three elements that always exist at the end of the node 'register' and I cant use the remove element because I want to keep the element before ('resetValue' , 'resetMask' and 'description')

I was hoping for a reslut like this:

<registers>
    <register>
      <name>reg1</name>
      <displayName>reg1</displayName>
      <description>This is register 1</description>
      <addressOffset>0x0</addressOffset>
      <size>32</size>
      <access>read-write</access>
      <resetValue>0x00000002</resetValue>
      <resetMask>0xFFFFFFFF</resetMask>
     <fields>
       .................
     </fields>
    </register>                           
    <register>
     <name>reg2</name>
     <displayName>reg2</displayName>
     <description>This is register 2</description>
     <addressOffset>0x0</addressOffset>
     <size>32</size>
     <access>read-write</access>
     <resetValue>0x00000000</resetValue>
     <resetMask>0xFFFFFFFF</resetMask>
      <fields>
           .................
      </fields>
     </register>
     <register>
         ..................
     </register>  
   </registers> 

Is it possible to only delete last element in xml? Can there be a solution with index since the position is always same (last 3 elements at the end of each 'register') but the elements exist before? Please advise me!

Thank you

1 Answers

Here is solution using lxml XPath API:

from lxml import etree as et
import itertools

# here variable xml is a string with the source XML from your question
root = et.fromstring(xml)

# create list of elements to be deleted
# itertools.chain() here creates one list from 3 lists returned by xpath() function calls
# predicate [last()] ensures that we select last element
elements = itertools.chain(
    root.xpath("//register/resetValue[last()]"),
    root.xpath("//register/resetMask[last()]"),
    root.xpath("//register/description[last()]"))

# iterate over selected elements and delete them
for el in elements:
  el.getparent().remove(el)

# output result
print (et.tostring(root, pretty_print=True, xml_declaration=True).decode('utf8'))

Output:

<?xml version='1.0' encoding='ASCII'?>
<component xmlns:xsi="http://www.w3.orgr">
  <memoryMaps>
    <memoryMap>
      <name>name</name>
      <description>description</description>
      <peripheral>
        <name>periph</name>
        <description>description</description>
        <baseAddress>0x0</baseAddress>
        <range>0x8</range>
        <width>32</width>
       <registers>
        <register>
          <name>reg1</name>
          <displayName>reg1</displayName>
          <description>This is register 1</description>
          <addressOffset>0x0</addressOffset>
          <size>32</size>
          <access>read-write</access>
          <resetValue>0x00000002</resetValue>
          <resetMask>0xFFFFFFFF</resetMask>
         <fields/>
         </register>                           
        <register>
          <name>reg2</name>
          <displayName>reg2</displayName>
          <description>This is register 2</description>
          <addressOffset>0x0</addressOffset>
          <size>32</size>
          <access>read-write</access>
          <resetValue>0x00000000</resetValue>
          <resetMask>0xFFFFFFFF</resetMask>
         <fields/>
         </register>
         <register>
         </register>  
       </registers>    
      </peripheral>
    </memoryMap>
  </memoryMaps>
</component>
Related