Каков наилучший способ построчного анализа XML-файла в Python без использования SAX? (iterparse ведет себя неожиданно)Python

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Каков наилучший способ построчного анализа XML-файла в Python без использования SAX? (iterparse ведет себя неожиданно)

Сообщение Anonymous »

Вопрос: Каков наилучший способ построчного анализа XML-файла в Python? Кажется, у меня есть обходной путь, но я хочу знать, есть ли лучшее, широко известное решение, чем мой несколько хакерский обходной путь.
Что я пробовал: Я бы предпочел не использовать SAX, потому что он требует большого количества запутанно структурированного шаблонного кода.
Способ iterparse (как из lxml.etree, так и из xml.etree .ElementTree) — это Как обсуждалось, это часто звучит так, как будто XML-файлы анализируются «итеративно», например, построчно.
Но оказывается, что на практике, если в качестве входных данных используется файлоподобный объект, оба парсера ищут и анализируют выходные данные метода .read этого файлового объекта. (В отличие от вывода .readline, как я ожидал.) Если этот файлоподобный объект является файловым указателем на файл размером 8 ГБ и он выполняется на узле кластера с памятью 2 ГБ, это, конечно, будет вызвать ошибку OOM.
Этот вывод основан на ответе на связанный вопрос, а также на моем собственном тестировании. Вот MWE:

Код: Выделить всё

import io
from lxml import etree
import xml.etree.ElementTree as etree2

xml_string = """







Manager

Star Team Member




"""

#### lxml output

for event, element in etree.iterparse(io.BytesIO(xml_string.encode("UTF-8")), recover=True, remove_blank_text=True,
events=("start", "end",)):
print(str((event, element, element.tag,
element.text.strip() if element.text is not None else element.text,
element.tail.strip() if element.tail is not None else element.tail)) + "\n")
print(f"{etree.tostring(element)}\n")

### xml.etree.ElementTree output is the same

for event, element in etree2.iterparse(io.BytesIO(xml_string.encode("UTF-8")),
events=("start", "end",)):
print(str((event, element, element.tag,
element.text.strip() if element.text is not None else element.text,
element.tail.strip() if element.tail is not None else element.tail)) + "\n")
print(f"{etree2.tostring(element)}\n")

Уже на самой первой итерации строковое представление корневого тега представляет весь XML-документ, что предполагает, что весь вывод .read уже проанализирован, а не чем просто первая строка (это то, чему я изначально думал, что первая итерация должна была соответствовать, основываясь на обсуждении iterparse другими).
Я смог прийти используйте следующий обходной путь, который отображает ожидаемое построчно поведение синтаксического анализа. Однако мне интересно, есть ли лучшие решения. Например, не вызовут ли миллионы вызовов readline, которые необходимо выполнить для файла размером ~8 ГБ, узкое место или ограничение ввода-вывода?

Код: Выделить всё

### for the MWE

class StreamString(object):

def __init__(self, string):
self._io = io.StringIO(string)

def read(self, len=None):
return self._io.readline().encode("UTF-8")

def close(self):
self._io.close()

### closer to what would be used in practice

class StreamFile(object):

def __init__(self, path):
self._file = open(path, "r")

def read(self, len=None):
return self._file.readline().encode("UTF-8")

def close(self):
self._file.close()

### demonstrating the expected line-by-line parsing behavior

iterator = etree.iterparse(StreamString(xml_string), recover=True, remove_blank_text=True,
events=("start", "end",))
event, root = next(iterator)
print(str((event, root, root.tag,
root.text.strip() if root.text is not None else root.text,
root.tail.strip() if root.tail is not None else root.tail)) + "\n")
print(f"{etree.tostring(root)}\n")

for event, element in iterator:
print(str((event, element, element.tag,
element.text.strip() if element.text is not None else element.text,
element.tail.strip() if element.tail is not None else element.tail)) + "\n")
print(f"{etree.tostring(root)}\n")

Это демонстрирует ожидаемое поведение, при котором проанализированное дерево, соответствующее корневому элементу, последовательно растет с каждой итерацией по мере добавления новых строк. Это поведение также легче понять и согласовать с многочисленными предложениями на этом сайте о том, как очистить следы памяти, соответствующие узлам и их предкам (и всем их «старшим» братьям и сестрам по поиску в глубину) после их анализа. Мне неясно, почему это не поведение по умолчанию.
Примечание: хотя строка XML, используемая для MWE, небольшая и легко помещается полностью в память, конечная цель — запустить эту для XML-файлов, размер которых потенциально составляет гигабайты, на узлах кластера с 1–2 ГБ памяти. (У меня нет контроля над вычислительной средой, да, я согласен, что было бы разумнее просто масштабировать вертикально до одного узла с памятью ~64 ГБ.)

Подробнее здесь: https://stackoverflow.com/questions/793 ... hout-using
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»