I'm looking to extract data from swimming results using python by un-nesting Lenex files (a form of xml).
The Lenex tree can be found here.
An example of a full file that I want to unnest can be found here.
More specifically, I would like to extract pieces of these files and convert them into dataframes - a table for each element (Athlete, Club, Result, etc.) where the columns are the attributes listed in the technical document linked above.
For example, the following code can get me a dataframe for Athletes with athleteid, lastname, firstname, gender, and birthdate as the columns:
tree = ET.parse(filepath)
root = tree.getroot()
athletes = pd.DataFrame()
for ele in root.findall(".//ATHLETE"):
df_dictionary = pd.DataFrame([ele.attrib])
athletes = pd.concat([athletes, df_dictionary], ignore_index=True)
The result looks like this (I've swapped names for initials):
| athleteid | lastname | firstname | gender | birthdate | |
|---|---|---|---|---|---|
| 0 | 145 | E | J | M | 2004-08-25 |
| 1 | 147 | M | C | M | 2003-12-16 |
| 2 | 146 | H | C | F | 2005-10-26 |
| 3 | 112 | P | J | M | 2004-11-22 |
| 4 | 111 | F | A | F | 2004-08-22 |
This is a good start, but each athlete is nested within a club. Also, within each athlete, is a collection of entries and results. Within each result, is a collection of splits. i.e. (Split < Result < Athlete < Club < Meet). I want to keep these associations when I turn this into dataframes.
My assumption is that the best way to do this is for the 'Split' dataframe to have an associated 'Resultid', for the 'Result' dataframe to have an associated 'Athleteid, and for the 'Athlete' dataframe to have an associated 'Clubid,' etc. Within any given meet, these relationships are true 'subsets,' i.e., it's a one-to-many relationship between results to splits, athletes to results, clubs to athletes, etc.
In terms of database design - Is this actually the most sensible way to do this?
More importantly, how would I add a column to my Athletes dataframe that includes their associated club name?
As far as a 'representative' example, I'm not sure if this is accurate or helpful, but I did my best to put something together:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<LENEX version="3.0">
<CONSTRUCTOR name="Swiss Timing Swimming Data Handling" version="60.0.0.0">
<CONTACT name="Swiss Timing Ltd." zip="CH-2606" city="Corgemont" email="info@swisstiming.com" internet="http://www.swisstiming.com" />
</CONSTRUCTOR>
<MEETS>
<MEET name="Phillips 66 International Team Trials" city="Greensboro, NC" nation="USA" course="LCM" timing="AUTOMATIC">
<SESSIONS>
<SESSION number="1" date="2022-04-26" daytime="09:00">
<EVENTS>
<EVENT eventid="112" number="12" preveventid="12" gender="M" round="FIN" daytime="18:57">
<SWIMSTYLE distance="200" relaycount="1" stroke="BACK" />
<HEATS>
<HEAT daytime="18:57" final="B" heatid="20112" number="2" />
<HEAT daytime="19:02" final="A" heatid="10112" number="1" />
<HEAT daytime="19:40" final="C" heatid="30112" number="3" />
</HEATS>
</EVENT>
</EVENTS>
</SESSION>
</SESSIONS>
<CLUBS>
<CLUB name=“An Aquatic Club” shortname="AAC" code="AAC" nation="USA" type="">
<ATHLETES>
<ATHLETE athleteid="145" lastname=“SMITH” firstname="John” gender="M" birthdate="2000-07-25">
<ENTRIES>
<ENTRY entrytime="00:01:55.31" eventid="12" heat="1" lane="4" />
</ENTRIES>
<RESULTS>
<RESULT eventid="112" place="12" lane="3" heat="2" heatid="20112" swimtime="00:02:00.20" reactiontime="+51">
<SPLITS>
<SPLIT distance="50" swimtime="00:00:28.31" />
<SPLIT distance="100" swimtime="00:00:58.62" />
<SPLIT distance="150" swimtime="00:01:29.61" />
<SPLIT distance="200" swimtime="00:02:00.20" />
</SPLITS>
</RESULT>
</RESULTS>
</ATHLETE>
</ATHLETES>
</CLUB>
</CLUBS>
</MEET>
</MEETS>
</LENEX>
The end goal should hopefully look something like this by modifying the code I'm currently using to generate the dataframe listed above:
| athleteid | lastname | firstname | gender | birthdate | club name | |
|---|---|---|---|---|---|---|
| 0 | 145 | Smith | John | M | 2004-07-25 | An Aquatic Club |
Thank you!