Разбор большого XML-файла и эффективное сохранение в Postgres с использованием кода Pythonic

У меня есть куча больших XML-файлов, которые мне нужно проанализировать и сохранить в Postgres. Я написал много процедурного кода, но хочу думать об объектах и ​​извлекать выгоду. Любая помощь в этом направлении приветствуется.

Сам XML довольно прост — каждый объект Person содержит информацию о работодателе, офисе работодателя, образовании. Мне интересно, как лучше всего создать класс Python для хранения этих данных с конечной целью эффективной вставки данных в Postgres.

Пример XML-файла

<?xml version="1.2" encoding="UTF-8"?>
<data>
    <person name="Mary Kitchen" personkey="123">
        <employers>
            <employer name="ABC Tech" id="767" startdate="02-2020" enddate="">
                <officeaddrs>
                    <officeaddr str1="101 MAIN ST" str2="" city="NYC" state="NY" zip="07789" />
                    <officeaddr str1="111 POOLE ST" str2="" city="NYC" state="NY" zip="07780" />
                </officeaddrs>
            </employer>
            <employer name="XYZ Tech" id="909"  startdate="06-2012" enddate="01-2020">
                <officeaddrs>
                    <officeaddr str1="122 Main St" str2="" city="NYC" state="NY" zip="07789" />
                    <officeaddr str1="199 Poole St" str2="" city="NYC" state="NY" zip="07780" />
                </officeaddrs>
            </employer>
        </employers>
        <educationrecords>
            <educationrecord type="Masters" school ="ABC School" graduated="12-14-2005"/>
            <educationrecord type="Bachelors" school ="XYZ School" graduated="12-14-2001"/>
        </educationrecords>
    </person>
    <person name="JASON KNIGHT" personkey="129">
        <employers>
            <employer name="NYState Bank" id="66" startdate="02-2015" enddate="">
                <officeaddrs>
                    <officeaddr str1="188 Main St" str2="" city="NYC" state="NY" zip="07789" />
                    <officeaddr str1="100 Poole St" str2="" city="NYC" state="NY" zip="07780" />
                </officeaddrs>
            </employer>
            <employer name="ZYK Tech" id="543" startdate="02-2010" enddate="01-2015">
                <officeaddrs>
                    <officeaddr str1="333 MAIN ST" str2="" city="NYC" state="NY" zip="07789" />
                </officeaddrs>
            </employer>
        </employers>
        <educationrecords>
            <educationrecord type="Bachelors" school ="Top School" graduated="04-01-2009"/>
        </educationrecords>
    </person>
</data>

Код Python

# import xml.etree.ElementTree as ET
from lxml import etree


def fast_iter(context, func, args=None, kwargs=None):
    # http://www.ibm.com/developerworks/xml/library/x-hiperfparse/
    # Author: Liza Daly
    if kwargs is None:
        kwargs = {}
    if args is None:
        args = []
    for event, elem in context:
        func(elem, *args, **kwargs)
        elem.clear()
        while elem.getprevious() is not None:
            del elem.getparent()[0]
    del context


class PersonParser:

    def __init__(self, element):
        self.element = element

    def myparser(self):
        print('hello')
        print(self.element)


class PersonData:

    def __init__(self, person=None, employer=None, office=None, education=None):
        self.person = person
        self.employer = employer
        self.office = office
        self.education = education


class Person:

    def __init__(self, personkey=None, name=None):
        self.name = name.title()
        self.personkey = personkey
        # print(self.name, self.personkey)

    def __repr__(self):
        return '(name={}, personkey={})'.format(
            self.name, self.personkey)


class Employer:

    def __init__(self, id=None, name=None, startdate=None, enddate=None):
        self.id = id
        self.name = name
        self.startdate = startdate
        self.enddate = enddate

    def __repr__(self):
        return f'(name={self.name}, id={self.id}, startdate={self.startdate}, enddate={self.enddate})'


class Office:

    def __init__(self, str1=None, str2=None, city=None, state=None, zip=None, personkey=None, empid=None):
        self.empid = empid
        self.personkey = personkey
        self.str1 = str1
        self.str2 = str2
        self.city = city
        self.state = state
        self.zip = zip
        # print(self.name, self.personkey)

    def __repr__(self):
        return '(name={}, personkey={})'.format(
            self.name, self.personkey)


class Education:

    def __init__(self, personkey=None, name=None):
        self.name = name
        self.personkey = personkey
        # print(self.name, self.personkey)

    def __repr__(self):
        return '(name={}, personkey={})'.format(
            self.name, self.personkey)


def myfunction(element):

    print(element)

    for person in element.iter('person'):
        # print('person', person.attrib)
        person_rec = person.attrib
        print(person_rec)

    for employer in element.iter('employer'):
        # print('employer', employer.attrib)
        employer_rec = employer.attrib
        employer_rec['personkey'] = person_rec['personkey']
        print(employer_rec)

        for office in employer.iter('officeaddr'):
            # print('office', office.attrib)
            office_rec = office.attrib
            office_rec['empid'] = employer_rec['id']
            office_rec['personkey'] = person_rec['personkey']
            print(office_rec)

    for education in element.iter('educationrecord'):
        # print('education', education.attrib)
        edu_rec = education.attrib
        edu_rec['personkey'] = person_rec['personkey']
        print(edu_rec)


def main():

    # tree = ET.parse('person_data.xml')
    context = etree.iterparse('person_data.xml', events=('end',), tag='person')
    fast_iter(context, myfunction)

    myPersonParser = PersonParser(context)
    myPersonParser.myparser()


if __name__ == "__main__":
    main()

Текущий выход

<Element person at 0x1006f9a40>
{'name': 'Mary Kitchen', 'personkey': '123'}
{'name': 'ABC Tech', 'id': '767', 'startdate': '02-2020', 'enddate': '', 'personkey': '123'}
{'str1': '101 MAIN ST', 'str2': '', 'city': 'NYC', 'state': 'NY', 'zip': '07789', 'empid': '767', 'personkey': '123'}
{'str1': '111 POOLE ST', 'str2': '', 'city': 'NYC', 'state': 'NY', 'zip': '07780', 'empid': '767', 'personkey': '123'}
{'name': 'XYZ Tech', 'id': '909', 'startdate': '06-2012', 'enddate': '01-2020', 'personkey': '123'}
{'str1': '122 Main St', 'str2': '', 'city': 'NYC', 'state': 'NY', 'zip': '07789', 'empid': '909', 'personkey': '123'}
{'str1': '199 Poole St', 'str2': '', 'city': 'NYC', 'state': 'NY', 'zip': '07780', 'empid': '909', 'personkey': '123'}
{'type': 'Masters', 'school': 'ABC School', 'graduated': '12-14-2005', 'personkey': '123'}
{'type': 'Bachelors', 'school': 'XYZ School', 'graduated': '12-14-2001', 'personkey': '123'}
  • Выгодно ли создавать класс для каждой таблицы (у меня будет список dicts для каждой таблицы, которую мне нужно массово хранить в Postgres, чтобы избежать многократных обходов), которые я хочу сохранить в базе данных?
  • Могу ли я создать экземпляр объекта в функции моя функция?
  • Как лучше всего загружать данные в Postgres оптом? Класс Person, который имеет все отдельные списки диктовок (работодатель, человек, офис, образование) в качестве переменных и метод загрузки данных в базу данных?

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *