Dane z XML do DataFrame – sax

W artykule opiszę jak wczytać dane z pliku XML do obiektu DataFrame przy użyciu modułu xml.sax.

Pliki projektu są do pobrania: >>tutaj<<

Używany jest identyczny plik XML, jaki opisałem we wcześniejszym wpisie.

Oprócz xml.sax używam jeszcze podobnie jak poprzednio moduł pandas oraz klasę defaultdict z modułu collections.

Pierwszym etapem przy odczycie danych z pliku XML przy użyciu SAX jest implementacja własnej klasy, która dziedziczy po klasie ContentHandler(). Klasa handlera przesłania trzy metody bazowej klasy: metodę startElement(), która wywoływana jest przy rozpoczęciu odczytu kolejnego taga, metodę characters(), która odczytuje wartości zapisane dla poszczególnego elementu oraz metodę endElement(), która jest wywoływana po zakończeniu odczytu odpowiedniego tagu. Oprócz tego w metodzie __init__() tworzę egzemplarz słownika, w którym będą zapisywane dane odczytane z pliku XML.

W metodzie startElement() definiuję atrybut klasy o nazwie tag, a także jeśli przetwarzanym tagiem jest ‘person’ zapisuję numer id dla osoby.

Następnie w metodzie characters() zapisuję wartości przechowywane w poszczególnych elementach jako odpowiednie zmienne klasy.

W metodzie endElement() zapisuję pobrane wartości do słownika persons.

Parsowanie pliku XML za pomocą modułu xml.sax polega na wywołaniu metody make_parser(), która zwraca instancję parsera. Następnie do utworzonego parsera jest jako argument funkcji setContentHandler przypisywana jest instancja handlera – w tym przypadku klasy PersonsHandler.

Następnie wywoływana jest metoda parse(), która dokonuje parsowania źródłowego dokumentu XML.

Zmienna persons przechowuje wartości słownika utworzonego przez handlera i ten słownik jest podawany jako parametr przy tworzeniu ramki DataFrame.

kod źródłowy:

import xml.sax
from collections import defaultdict
import pandas as pd

class PersonsHandler(xml.sax.ContentHandler):
    def __init__(self):
        self.persons = defaultdict(list)
    def startElement(self, tag, attr):
        self.tag = tag
        if tag == 'person':
            self.persons['id'].append(attr['id'])
            
    def characters(self, content):
        if content.strip():
            if self.tag == 'position': self.position = content
            elif self.tag == 'first_name': self.first_name = content
            elif self.tag == 'last_name': self.last_name = content
            elif self.tag == 'email': self.email = content
            elif self.tag == 'salary': self.salary = content
    
    def endElement(self, tag):
        if tag == 'position': self.persons['position'].append(self.position)
        elif tag == 'first_name': self.persons['first_name'].append(self.first_name)
        elif tag == 'last_name': self.persons['last_name'].append(self.last_name)
        elif tag == 'email': self.persons['email'].append(self.email)
        elif tag == 'salary': self.persons['salary'].append(self.salary)

parser = xml.sax.make_parser()
parser.setContentHandler(PersonsHandler())
parser.parse(open('persons.xml'))
persons = parser.getContentHandler().persons


df = pd.DataFrame(persons, columns=persons.keys()).set_index('id')
df['salary'] = df['salary'].astype(float)
print(df.sort_values(by='salary', ascending=False))

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *