Home > Blockchain >  How to access nested XML tags for comparision using Python?
How to access nested XML tags for comparision using Python?

Time:08-01

I have this original XML which needs to be modified

            <COUNTRY>
                <NAME>Place ="MALTA"</NAME>
                <DETAILS ID = "tag1"/>
                    <EUROPE CAPITAL="Valletta" />
                    <EUROPE population=123456 />
                    <EUROPE tag = "new"/>
                </DETAILS>
                <DETAILS ID = "tag2"/>
                    <EUROPE CAPITAL="NEW_CAPITAL" />
                    <EUROPE GDP=66666666 />
                    <EUROPE tag = "new"/>
                </DETAILS>
                <DETAILS ID = "tag3"/>
                    <EUROPE CLIMATE="Warm" />
                    <EUROPE Votes=123 />
                    <EUROPE tag = "new"/>
                </DETAILS>
            </COUNTRY>

Now I need to modify this XML after comparing the tags,here I need to compare COUNTRY/DETAILS/ID tag for example: if ID == "tag1" add a new tag(<EUROPE tag = "tag1"/>). If ID == tag2 need to add(<EUROPE tag = "tag2"/>). Basically I'm trying to modify a particular block of XML using its "TEXT" as a reference instead of TAG or its ATTRIBUTE. TL;DR - Explanation might be a lil confusing, the tried approach code below might be beneficial.

           <COUNTRY>
                <NAME>Place ="MALTA"</NAME>
                <DETAILS ID = "tag1"/>
                    <EUROPE CAPITAL="Valletta" />
                    <EUROPE population=123456 />
                    <EUROPE tag = "new"/>
                    <EUROPE tag = "tag1"/>
                </DETAILS>
                <DETAILS ID = "tag2"/>
                    <EUROPE CAPITAL="NEW_CAPITAL" />
                    <EUROPE GDP=66666666 />
                    <EUROPE tag = "new"/>
                    <EUROPE tag = "tag2"/>
                </DETAILS>
                <DETAILS ID = "tag3"/>
                    <EUROPE CLIMATE="Warm" />
                    <EUROPE Votes=123 />
                    <EUROPE tag = "new"/>
                </DETAILS>
            </COUNTRY>

STEP1 - Compare the tag to ID(If ID == "tag1")

STEP2 - do something if successful(in this case add <EUROPE tag = "tag1"/>)

I tried the below approach but wasn't successful.When I try to iterate through "details" variable, it's empty. Not sure if it's able to populate specified XML entries.

tree = ET.parse('abc.xml')
root = tree.getroot()
details= tree.findall(".//COUNTRY[DETAILS='ID:\"tag1\"')
for d in details:
     d.append(ET.fromstring('<EUROPE tag = "tag1"/>'))
details2= tree.findall(".//COUNTRY[DETAILS='ID:\"tag2\"')
for d in details2:
     d.append(ET.fromstring('<EUROPE tag = "tag2"/>'))

CodePudding user response:

As mentioned in comments to your question, both your sample xml and expected output are not well formed. But assuming your sample xml is fixed like so:

<COUNTRY>
  <NAME>Place ="MALTA"
  </NAME>
  <DETAILS ID = "tag1">
    <EUROPE CAPITAL="Valletta" />
    <EUROPE population="123456" />
    <EUROPE tag = "new"/>
  </DETAILS>
  <DETAILS ID = "tag2">
    <EUROPE CAPITAL="NEW_CAPITAL" />
    <EUROPE GDP="66666666" />
    <EUROPE tag = "new"/>
  </DETAILS>
  <DETAILS ID = "tag3">
    <EUROPE CLIMATE="Warm" />
    <EUROPE Votes="123" />
  </DETAILS>
</COUNTRY>

and that I understand your question correctly, your main issue is with your xpath expression .//COUNTRY[DETAILS='ID:\"tag1\", which seems to confuse elements and attributes. This should work:

for country in root.findall('.//DETAILS'):
    new_euo = ET.fromstring(f'<EUROPE tag = "{country.get("ID")}"/>')
    size = len(country.findall('.//*'))
    #size is necessary to determine the insertion place, since the number
    #of <EUROPE> children seems to change in each <DETAILS>
    country.insert(size,new_euo)
    ET.indent(root, space=' ', level=2) 
    #indent() works with python 3.9 and above; otherwise - just delete it                          
print(ET.tostring(root).decode())

Output:

<COUNTRY>
   <NAME>Place ="MALTA"</NAME>
   <DETAILS ID="tag1">
    <EUROPE CAPITAL="Valletta" />
    <EUROPE population="123456" />
    <EUROPE tag="new" />
    <EUROPE tag="tag1" />
   </DETAILS>
   <DETAILS ID="tag2">
    <EUROPE CAPITAL="NEW_CAPITAL" />
    <EUROPE GDP="66666666" />
    <EUROPE tag="new" />
    <EUROPE tag="tag2" />
   </DETAILS>
   <DETAILS ID="tag3">
    <EUROPE CLIMATE="Warm" />
    <EUROPE Votes="123" />
    <EUROPE tag="tag3" />
   </DETAILS>
  </COUNTRY>
  • Related