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

Using Python xmltree to sort child elements by attribute value containing FLOAT values?

This is and example of the XML for Pioneer Rekordbox DJ Software.

  • Using Python, I am trying to re-sort the XML child tags by the START attribute for each POSITION_MARK tag. The POSITION MARK tag basically represent cue points for the DJ software.

I looked at this Stackoverflow question, but they only sort by whole numbers, not floats:

Python sort XML elements by and tag and attributes recursively

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

But I need to sort by the float value in each attribute.

  • Each TRACK tag has POSITION_MARK child tags with a Start attribute float value.
  • How do you re-sort the POSITION_MARK child tags by there float number in the Start attribute.
  • This way when it rewrites the XML, each TRACK tags POSITION_MARK children are sorted in ascending order (smallest to largest) by their Start attribute value which is a float value.

How do you sort in Python using xmltree sorted to re-sort the POSITION_MARK children by their START attribute that contain float values?

<?xml version="1.0" ?>
<DJ_PLAYLISTS>
    <COLLECTION>

       <TRACK>        
          <POSITION_MARK Start="22.093" />
          <POSITION_MARK Start="44.162" />
          <POSITION_MARK Start="88.300" />
          <POSITION_MARK Start="110.369" />
          <POSITION_MARK Start="132.438" />
          <POSITION_MARK Start="11.059" />
          <POSITION_MARK Start="220.714" />
          <POSITION_MARK Start="242.783" />
       </TRACK>
    
       <TRACK>        
          <POSITION_MARM Start="0.024" />
          <POSITION_MARK Start="30.024" />
          <POSITION_MARK Start="60.024" />
          <POSITION_MARK Start="90.024" />
          <POSITION_MARK Start="120.024" />
          <POSITION_MARK Start="150.024" />
          <POSITION_MARK Start="180.024" />
       </TRACK>

    </COLLECTION>
 </DJ_PLAYLISTS>

>Solution :

xml.etree.ElementTree.Element objets are designed to look / feel like lists. Sadly they are not actually lists, and don’t support list.sort, however if you slice them you do get a list of sub-elements in the range. So given an element e, e[:] will return a list of all its children elements.

You can then sort that in-place, then use slice-setting (e[:] = ...) to replace the existing sequence of children by the now-sorted list.

doc = ET.fromstring(doc)
# iterate all the TRACK elements
for track in doc.iterfind(".//TRACK"):
    # get a list of the track's children (POSITION_MARK)
    children = track[:]
    # sort in place, using the `Start` attribute interpreted as a float (by actually parsing it to a float)
    children.sort(key=lambda e: float(e.get('Start')))
    # set the now-sorted children back on
    track[:] = children
print(ET.tostring(doc, encoding='unicode'))

However, sorted takes an iterable, which an Element is, so you can use that to get-and-sort the sub-elements in a single operation. And since it also returns a list, you can then directly set the result back as above:

doc = ET.fromstring(doc)
for track in doc.iterfind(".//TRACK"):
    track[:] = sorted(track, key=lambda e: float(e.get('Start')))
print(ET.tostring(doc, encoding='unicode'))
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