У меня есть куча больших 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, который имеет все отдельные списки диктовок (работодатель, человек, офис, образование) в качестве переменных и метод загрузки данных в базу данных?