TeaBoneJones TeaBoneJones - 1 month ago 4
Python Question

Sort XML by value with python

Here is the XML I'm working with:

<hotspot>
<position>
<pan>-102.698</pan>
<tilt>-62.5853</tilt>
</position>
<next>
<pan>0</pan>
<tilt>0</tilt>
<fov>70</fov>
</next>
<polygon/>
<type>point</type>
<id>Test Name 1</id>
<title>Test Name 1</title>
<linktype>info</linktype>
<skinid>skin-id-1</skinid>
</hotspot>
<hotspot>
<position>
<pan>-109.553</pan>
<tilt>-69.7479</tilt>
</position>
<next>
<pan>0</pan>
<tilt>0</tilt>
<fov>70</fov>
</next>
<polygon/>
<type>point</type>
<id>Test Name 2</id>
<title>Test Name 2</title>
<linktype>info</linktype>
<skinid>skin-id-1</skinid>
</hotspot>
<hotspot>
<position>
<pan>-95.4268</pan>
<tilt>-55.4989</tilt>
</position>
<next>
<pan>0</pan>
<tilt>0</tilt>
<fov>70</fov>
</next>
<polygon/>
<type>point</type>
<id>Test Name 3</id>
<title>Test Name 3</title>
<linktype>info</linktype>
<skinid>skin-id-1</skinid>
</hotspot>


What I'm trying to do is sort everything within the "hotspot" tags by the "tilt" tag under the "position" tag, NOT the "tilt" tag under the "next" tag.

This is how I want it to look:

<hotspot>
<position>
<pan>-109.553</pan>
<tilt>-69.7479</tilt>
</position>
<next>
<pan>0</pan>
<tilt>0</tilt>
<fov>70</fov>
</next>
<polygon/>
<type>point</type>
<id>Test Name 2</id>
<title>Test Name 2</title>
<linktype>info</linktype>
<skinid>skin-id-1</skinid>
</hotspot>
<hotspot>
<position>
<pan>-102.698</pan>
<tilt>-62.5853</tilt>
</position>
<next>
<pan>0</pan>
<tilt>0</tilt>
<fov>70</fov>
</next>
<polygon/>
<type>point</type>
<id>Test Name 1</id>
<title>Test Name 1</title>
<linktype>info</linktype>
<skinid>skin-id-1</skinid>
</hotspot>
<hotspot>
<position>
<pan>-95.4268</pan>
<tilt>-55.4989</tilt>
</position>
<next>
<pan>0</pan>
<tilt>0</tilt>
<fov>70</fov>
</next>
<polygon/>
<type>point</type>
<id>Test Name 3</id>
<title>Test Name 3</title>
<linktype>info</linktype>
<skinid>skin-id-1</skinid>
</hotspot>


I was hoping to achieve this with python, but if there's a better way, let me know. Thanks!

Answer

This program might do what you want:

from lxml import etree

# Read the file in
with open('x.xml') as in_file:
    xml = etree.parse(in_file)
    root = xml.getroot()

# sort the data according to the criteria
root[:] = sorted(
    root[:],
    key=lambda hotspot: float(hotspot.find('./position/tilt').text))

# Write the file out
with open('x-out.xml', 'w') as out_file:
    xml.write(out_file)

This program assumes that your XML has the following form:

<root>
    <hotspot> ... </hotspot>
    <hotspot> ... </hotspot>
    ...
   <hotspot> ... </hotspot>
</root>
Comments