Ошибка памяти при восстановлении поврежденного xml - PullRequest
0 голосов
/ 19 февраля 2020

У меня есть неправильный XML, который очень велик - в нем нет тега верхнего уровня и есть дубликаты атрибутов. Чтобы обойти это, я протестировал следующее решение на подмножестве моего искаженного XML, и оно отлично работает для добавления тега и автоматического удаления дублирующихся атрибутов, используя BeautifulSoup.

import sys
from bs4 import BeautifulSoup
import xml.etree.ElementTree as ET

flow_file = sys.stdin.read()

try:
    tree = ET.fromstring(flow_file)
    sys.stdout.write(flow_file)
except:
    flow_file = f"<dispatch>{flow_file}</dispatch>"
    soup = BeautifulSoup(flow_file, 'xml')
    sys.stdout.write(soup)

Однако, поскольку мой реальный файл настолько большой, он выдает ошибку памяти. Поскольку мне нужно (AFAICT) полный XML для добавления тегов верхнего уровня и удаления дубликатов, я не совсем уверен, как изменить мой код для обработки таких больших XML. Я видел несколько предложений по использованию lxml и итерации, но мне не ясно, как это вписывается в мои потребности / процессы.

ETA: не уверен, что полезно, но весь смысл в том, чтобы очистить файл, чтобы он мог работать через процессор SplitXML NiFi.

1 Ответ

0 голосов
/ 20 февраля 2020

Поскольку я действительно не знаю, что вы делаете с данными, вот подход, который я использовал для большого xml файла размером в несколько ГБ:

import xml.etree.ElementTree as etree

root = False
#iterparse file, get event tags start and end
for event, elem in etree.iterparse("my_big.xml", events=('start', 'end')):
#set first element as rootelement, so we can clear it later
    if event == "start" and root == "False":
        root = elem
#Here we look for a certain end tag
    if event == "end" and elem.tag == "TAGOFINTEREST":
#set found False, so we can break, as soon, as we found our DataOfInterest
        found = False
#iterate through children and iterate over child nodes
#HERE I guess you would work with pandas
        for stuff in elem.getchildren():
#if found == True stop iterating or whatever condition you have
            if found:
                break
             #look for what you need, set found to True and break the 
             found = True
#clear elem, in order to save RAM
        elem.clear()

#Might require revision clears RAM after every "end" event
    if event == "end":
        root.clear()

Надеюсь, это поможет.

...