Комментарий : поскольку теперь он выводит только результаты
Вывод результатов предназначен только для демонстрации, трассировки и отладки.
Для записи record
иaddresses
в базу данных SQL
, например, используя sqlite3
, выполните:
c.execute("INSERT INTO entity(id, name) VALUES(:id, :name)", record)
addresses = []
for addr in record['addresses']:
addr[1].update({'id': record['id']})
addresses.append(addr[1])
c.executemany("INSERT INTO adresses(id, address, city) VALUES(:id, :address, :city)", addresses)
Чтобы сгладить панд
Preconditon внецикл: df = pd.DataFrame()
from copy import copy
addresses = copy(record['addresses'])
del record['addresses']
df_records = []
for addr in addresses:
record.update(addr[1])
df_records.append(record)
df = df.append(df_records, ignore_index=True)
Вопрос : Используйте etree.iterparse
, чтобы включить все узлы в файл XML
Следующее class Entity
do:
- Разобрать файл
XML
, используя lxml.etree.iterparse
. - Существует нет ограничения на размер файла , поскольку
<entity>...</entity>
Дерево элементов удаляется после обработки . - Строится из каждого
<entity>...</entity>
дерева dict {tag, value, ...}
. - Использование от
generator objects
до yield
dict
. - Элементы последовательности, например,
<addresses>/<address>
- Список кортежей [(address, {tag, text})...
.
ToDo :
- Чтобы объединить во многих записях, цикл
record['addresses']
- Чтобы выровнять разные имена тегов:
address
и address1
- Для выравнивания теги последовательности, например
<titels>
, <probs>
и <dobs>
from lxml import etree
class Entity:
def __init__(self, fh):
"""
Initialize 'iterparse' to only generate 'end' events on tag '<entity>'
:param fh: File Handle from the XML File to parse
"""
self.context = etree.iterparse(fh, events=("end",), tag=['entity'])
def _parse(self):
"""
Parse the XML File for all '<entity>...</entity>' Elements
Clear/Delete the Element Tree after processing
:return: Yield the current '<entity>...</entity>' Element Tree
"""
for event, elem in self.context:
yield elem
elem.clear()
while elem.getprevious() is not None:
del elem.getparent()[0]
def sequence(self, elements):
"""
Expand a Sequence Element, e.g. <titels> to a Tuple ('titel', text).
If found a nested Sequence Element, e.g. <address>,
to a Tuple ('address', {tag, text})
:param elements: The Sequence Element
:return: List of Tuple [(tag1, value), (tag2, value), ... ,(tagn, value))
"""
_elements = []
for elem in elements:
if len(elem):
_elements.append((elem.tag, dict(self.sequence(elem))))
else:
_elements.append((elem.tag, elem.text))
return _elements
def __iter__(self):
"""
Iterate all '<entity>...</entity>' Element Trees yielded from self._parse()
:return: Dict var 'entity' {tag1, value, tag2, value, ... ,tagn, value}}
"""
for xml_entity in self._parse():
entity = {'id': xml_entity.attrib['id']}
for elem in xml_entity:
# if elem is Sequence
if len(elem):
# Append tuple(tag, value)
entity[elem.tag] = self.sequence(elem)
else:
entity[elem.tag] = elem.text
yield entity
if __name__ == "__main__":
with open('.\\FILE.XML', 'rb') as in_xml_
for record in Entity(in_xml):
print("record:{}".format(record))
for key, value in record.items():
if isinstance(value, (list)):
#print_list(key, value)
print("{}:{}".format(key, value))
else:
print("{}:{}".format(key, value))
Выход : Показывает только первую запись и только 4 полей.
Примечание : есть ловушка с уникальными именами тегов: address
и address1
record:{'id': '1124353', 'titles': {'title': 'Foot... (omitted for brevity)
id:1124353
name:DAVID, Beckham
titles:[('title', 'Football player')]
addresses:
address:{'city': 'London', 'address': None, 'post... (omitted for brevity)
address:{'city': 'London', 'address1': '35-37 Par... (omitted for brevity)
Протестировано с Python: 3,5 - lxml.etree: 3.7.1