Разобрать самозакрывающиеся теги без знака "/" - PullRequest
1 голос
/ 14 мая 2019

Я пытаюсь проанализировать старый код SGML с помощью BeautifulSoup4 и построить дерево элементов с данными. В основном это работает нормально, но некоторые теги, которые должны быть самозакрывающимися, не помечены как таковые. Например:

<element1>
    <element2 attr="0">
    <element3>Data</element3>
</element1>

Когда я анализирую данные, они заканчиваются примерно так:

<element1>
    <element2 attr="0">
        <element3>Data</element3>
    </element2>
</element1>

Я хотел бы, чтобы он предположил, что если он не находит закрывающий тег для таких элементов, он должен обрабатывать его как самозакрывающийся тег, а не предполагать, что все после него является дочерним, и помещать закрывающий тег пометить как можно позже, например:

<element1>
    <element2 attr="0"/>
    <element3>Data</element3>
</element1>

Может ли кто-нибудь указать мне на парсер, который мог бы это сделать, или каким-то образом изменить существующий, чтобы он действовал таким образом? Я перерыл несколько парсеров (lxml, lxml-xml, html5lib), но не могу понять, как получить эти результаты.

1 Ответ

1 голос
/ 15 мая 2019

Я закончил тем, что извлек все пустые элементы, где конечный тег может быть опущен из DTD (например, <!ELEMENT elem_name - o EMPTY >), создал список из этих элементов, а затем с помощью регулярных выражений закрыл все теги в списке. Полученный текст затем передается анализатору XML.

Вот урезанная версия того, что я делаю:

import re
from lxml.html import soupparser
from lxml import etree as ET

empty_tags = ['elem1', 'elem2', 'elem3']

markup = """
<elem1 attr="some value">
<elem2/>
<elem3></elem3>
"""

for t in empty_tags:
    markup = re.sub(r'(<{0}(?:>|\s+[^>/]*))>\s*(?:</{0}>)?\n?'.format(t), r'\1/>\n', markup)

tree = soupparser.fromstring(markup)
print(ET.tostring(tree, pretty_print=True).decode("utf-8"))

Вывод должен быть:

<elem1 attr="some value"/>
<elem2/>
<elem3/>

(На самом деле это будет заключено в теги, но парсер добавляет их в.)

Он оставит атрибуты в покое и не будет касаться тегов, которые уже закрыты. Если у тега есть закрывающий тег, но он пуст, он удалит закрывающий тег и автоматически закроет тег, просто чтобы он был стандартизирован.

Это не очень общее решение, но, насколько я могу судить, нет другого способа сделать это, не зная, какие теги должны быть закрыты. Даже OpenSP нужен DTD, чтобы знать, какие теги он должен закрывать.

...