Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Python: Sort XML attributes alphabetically within element without sorting elements

I’m looking for some help with sorting XML files in Python 3.12. I’ve found some examples of sorting, but so far none have been very applicable to what I’m looking to do (whether focusing on sorting elements, sorting only specific attributes, etc.). The closest example I could find was this, but it didn’t really seem to work for what I’m trying to do, I think because it seems to be looking based on specific attributes rather than any attribute.

I want to sort every attribute within each element by the attribute name (not value), without changing the order of any elements. (I think I used the right names to describe the parts of the XML file, but if there’s confusion, I can clarify).

Here’s an example:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Starting file:

<PowerStyle IconFile="textures/ui/wolverine_all.png" IconColumns="2" IconRows="2" CanSteal="true" exclusive="wolverine">
    <FightMove Name="fastball" lockangles="true" sequenced="true" animenum="ea_lunge" playspeed="2" handler="ch_fastball">
        <trigger time="-1" tag="1" name="punch" PowerAttack="true" arc="180" Knockback="K3" Damage="L3">
            <damageMod name="dmgmod_auto_knockback" />
        </trigger>
        <chain action="special2" result="fastballhit" />
        <chain action="touch" result="fastballhit" />
        <chain action="idle" result="fastballland" />
    </FightMove>
    <FightMove Name="fastballhit" lockangles="true" animenum="ea_jump_smash_land" lockchaining="true" startchaintime="0.8">
        <chain action="idle" result="idle" />
    </FightMove>
...

Desired Output:

<PowerStyle CanSteal="true" exclusive="wolverine" IconColumns="2" IconFile="textures/ui/wolverine_all.png" IconRows="2">
    <FightMove animenum="ea_lunge" handler="ch_fastball" lockangles="true" Name="fastball" playspeed="2" sequenced="true" >
        <trigger arc="180" Damage="L3" Knockback="K3" name="punch" PowerAttack="true" tag="1" time="-1">
            <damageMod name="dmgmod_auto_knockback" />
        </trigger>
        <chain action="special2" result="fastballhit" />
        <chain action="touch" result="fastballhit" />
        <chain action="idle" result="fastballland" />
    </FightMove>
    <FightMove animenum="ea_jump_smash_land" lockangles="true" lockchaining="true" Name="fastballhit" startchaintime="0.8">
        <chain action="idle" result="idle" />
    </FightMove>
...

I know that the order of the attributes doesn’t really matter, but this is mainly for readability and for aligning the style with file content from a similar game. I’d like for capitalization to be maintained, but I’d like for the attributes to be sorted without considering the capitalization (purely alphabetically). So for example, in the first FightMove element, the order of attributes goes from Name, lockangles, sequenced, animenum, playspeed, handler to animenum, handler, lockangles, Name, playspeed, sequenced. However, the child elements of the first FightMove element (trigger and 3 chain elements), do not change their order.

If any additional clarity is needed to help define the problem, I can definitely provide it.

>Solution :

You can write a helper method which will sort a xml for you .

import xml.etree.ElementTree as ET

def sort_attributes(element):
    sorted_attrib = dict(sorted(element.attrib.items(), key=lambda item: item[0].lower()))
    element.attrib.clear()
    element.attrib.update(sorted_attrib)

    for child in element:
        sort_attributes(child)

def sort_xml(xml_string):
    root = ET.fromstring(xml_string)

    sort_attributes(root)

    return ET.tostring(root, encoding="unicode")

The method sort_xml should sort attributes alphabetically case insensitive.

If you need a copy of the XML, make sure to use copy.deepcopy on the original data, as the dict type is a reference type.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading