l xml: не анализировать поддерево, а рассматривать как двоичный контент - PullRequest
0 голосов
/ 06 февраля 2020

Я работаю над XML контентом, который содержит элементы, которые могут содержать потенциально искаженный XML / подобный разметке (например, HTML) контент в виде текста. Например:

<root>
    <data>
        <x>foo<y>bar</y>
    </data>
    <data>
        <z>foo<y>bar</y>
    </data>
</root>

Цель : я хочу, чтобы lxml.etree не пытался анализировать что-либо под data -элементами как XML, а просто возвращал его как bytes или str (может быть в elem.text).

Файлы большие, и я хотел использовать lxml.etree.iterparse для извлечения содержимого, найденного в data - элементах.

Начальная идея : простой способ просто получить содержимое элемента (в данном случае содержащий data начальный и конечный теги) может быть:

data = BytesIO(b"""
<root>
    <data>
        <x>foo<y>bar</y>
    </data>
    <data>
        <z>foo<y>bar</y>
    </data>
</root>
""")

from lxml import etree

# see below why html=True
context = etree.iterparse(data, events=("end",), tag=("data",), html=True)
contents = []  # I don't keep lists in the "real" application
for event, elem in context:
    contents.append(etree.tostring(elem))  # get back the full content underneath data

проблема в том, что lxml.etree может столкнуться с проблемами при разборе потомков data (например: мне уже пришлось использовать html=True, чтобы не столкнуться с проблемами, когда html -данные хранятся в data). Я знаю, что есть классы пользовательских элементов в lxml, но насколько я понимаю в документации, они не меняют поведение синтаксического анализа lxml.etree, продиктованное libxml2).

Есть ли простой способ сказать lxml не пытаться анализировать содержимое элемента как дочерние. Само приложение извлекает выгоду из других lxml функций, которые мне пришлось бы тиражировать, если бы я написал собственный экстрактор только для data.

Или мог бы быть способ использовать XSLT для первого преобразования ввода для обработки в lxml и позже связать данные?

1 Ответ

1 голос
/ 06 февраля 2020

Работает ли это как ожидалось? XML модифицируется добавлением DTD и CDATA, чтобы указать, что содержимое внутри элемента данных должно обрабатываться как символьные данные.

data = io.BytesIO(B'''<?xml version='1.0' encoding='UTF-8'?>

<!DOCTYPE root [
<!ELEMENT root (data+)>
<!ELEMENT data (#PCDATA)>
]>

<root>
    <data>
        <![CDATA[
        <x>foo<y>bar</y>
        ]]>
    </data>
    <data>
        <![CDATA[
        <z>foo<y>bar</y>
        ]]>
    </data>
</root>

''')

from lxml import etree

# see below why html=True
context = etree.iterparse(data, events=("end",), tag=("data",), dtd_validation=True, load_dtd=True)
contents = []  # I don't keep lists in the "real" application
for event, elem in context:
    contents.append(etree.tostring(elem))  # get back the full content underneath data
...