Как правильно обрабатывать текстовые элементы с помощью iterparse () в LXML? - PullRequest
0 голосов
/ 24 сентября 2018

Вот простой XML-файл:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
  <someThing>
    Text A: This is a test line.
    <p>Some paragraph.</p>
    Text B: This is another test line.
    <p>Some other paragraph.</p>
    Text C: And even another test line.
  </someThing>
</root>

Хотя тестовый XML-файл очень мал, реальный файл, который я хотел бы обработать, довольно велик: несколько гигабайт.Поэтому я хотел бы проанализировать этот файл, используя iterparse (), используя следующий код Python.

import xml.etree.ElementTree as etree
FILE_NAME = "test.xml"
for event, element in etree.iterparse(FILE_NAME, events=("start", "end", "start-ns", "end-ns")):
        print(event, "\t", element, "\t", repr(element.text))

Если я запустил это, я получу следующий вывод:

start    <Element 'root' at 0x7fd96a6aa728>      '\n\t'
start    <Element 'someThing' at 0x7fd968fba688>     '\n\t\tText A: This is a test line.\n\t\t'
start    <Element 'p' at 0x7fd968fcaf48>     'Some paragraph.'
end      <Element 'p' at 0x7fd968fcaf48>     'Some paragraph.'
start    <Element 'p' at 0x7fd968fcaf98>     'Some other paragraph.'
end      <Element 'p' at 0x7fd968fcaf98>     'Some other paragraph.'
end      <Element 'someThing' at 0x7fd968fba688>     '\n\t\tText A: This is a test line.\n\t\t'
end      <Element 'root' at 0x7fd96a6aa728>      '\n\t'

Как вы можете видетьтекстовые элементы после <p> -элементов игнорируются.

Мой вопрос: как мне использовать API LXML для правильной обработки содержимого этого файла?Все примеры, которые я мог найти до сих пор по этой теме, не делают ничего, кроме моего короткого фрагмента кода, и поэтому страдают от той же проблемы.Если это невозможно сделать с помощью LXML, кто-нибудь знает другой разборщик XML, который я мог бы использовать, и приведу краткий пример?

1 Ответ

0 голосов
/ 24 сентября 2018

Согласно доброму комментарию пользователя mzjn вы можете сделать это с LXML: к атрибуту tail добавлен отсутствующий текст.Но, вероятно, это не лучший способ сделать это из-за следующих причин:

  • LXML неизбежно создаст большое дерево (которое частично может быть обрезано вручную, конечно, во время обработки событий, ноэто далеко не оптимально)
  • Нет единого события для разбора текста между двумя элементами, поэтому вам придется обойти это, проанализировав tail.

Альтернативное решение: Сделайте это напрямую с SAX API.

Пример:

import xml.sax

FILE_NAME = "test.xml"

class MyHandler(xml.sax.handler.ContentHandler):

    def startElement(self, name, attrs):
        print("startElement\t" + repr(name))

    def endElement(self, name):
        print("endElement\t" + repr(name))

    def startElementNS(self, name, qname, attrs):
        print("startElementNS\t" + repr(name))

    def endElementNS(self, name, qname):
        print("endElementNS\t" + repr(name))

    def characters(self, content):
        print("  chars\t\t" + repr(content))

contentHandler = MyHandler()
xml.sax.parse(FILE_NAME, contentHandler)

Этот пример выше будет хорошей отправной точкой для обработки огромных файлов XML.Метод characters() будет вызываться для каждого проанализированного фрагмента текста.Объекты декодируются и также вызывают characters(), поэтому легко собрать весь текст, хранящийся в элементе XML.Если в вашем обработчике контента реализован простой стек, который увеличивается и уменьшается при вызовах startElement() и endElement(), вы можете легко проанализировать определенные части дерева и пропустить то, что вам не нужно обрабатывать.

...