Поддерживает ли lxml использование нестандартного синтаксического анализатора не-XML, не-HTML? - PullRequest
0 голосов
/ 24 октября 2019

Мне нужно проанализировать почти XML-подобные данные в Python

[tag]text [anothertag]anothertext[/anothertag][/tag]

Я понял, что в xml.etree.ElementTree можно передать собственный анализатор в функцию fromstring(string, parser). Хотя мне нужно использовать lxml.etree из-за поддержки XSLT. Я не могу передать парсер, я могу использовать только другой класс вместо Element класса, но это не имеет ничего общего с анализом.

Есть ли способ реализовать мой собственный синтаксический анализатор для lxml?

PS Пожалуйста, не ссылайтесь на пример "гудка" - это не имеет смысла для меня.

PPS Изменение [ на < не поможет, в то время как синтаксический анализатор должен работать также с вводом

[tag]text [anothertag]anothertext[/tag][/anothertag]

1 Ответ

0 голосов
/ 24 октября 2019

Вы можете использовать анализатор HTML из lxml, который допускает неправильное вложение, но для этого вам придется заменить квадратные скобки на заостренные и убедиться, что из этого не выйдут никакие невозможные теги HTML, такие как <'>.

Можно использовать регулярное выражение и выбрать замещающие строки с помощью функции. Не зная вашего целевого формата, я создаю его.

import re
import lxml.html

LINGVO_TAG_EXPR = re.compile(r'\[(\/?)([^\s\]]+)([^]]*)\]')

def lingvo_to_html(match):
    groups = match.groups()
    is_closing = groups[0] != ''
    tag = groups[1].lower()
    args = groups[2].strip()
    if tag == '*':
        htmltag = 'span'
        htmlargs = 'class="fulltranslation"'
    elif tag == 'm':
        htmltag = 'div'
        htmlargs = 'class="margin_%s"' % args
    elif tag == 'trn':
        htmltag = 'div'
        htmlargs = 'class="translations"'
    elif tag == 'ex':
        htmltag = 'div'
        htmlargs = 'class="examples"'
    elif tag == 'com':
        htmltag = 'div'
        htmlargs = 'class="comments"'
    elif tag == 's':
        htmltag = 'div'
        htmlargs = 'class="multimedia"'
    elif tag == 'url':
        htmltag = 'a'
        htmlargs = 'href="%s"' % args.replace('"', '&quot;')
    elif tag == '!trs':
        htmltag = 'span'
        htmlargs = 'class="noindex"'
    elif tag == 'p':
        htmltag = 'div'
        htmlargs = 'class="label"'
    elif tag == '\'':
        htmltag = 'span'
        htmlargs = 'class="stressed"'
    else:
        htmltag = tag
        htmlargs = args

    if is_closing:
        return '</' + htmltag + '>'
    else:
        return '<' + (htmltag + ' ' + htmlargs).strip() + '>'

def parse_lingvo(dsl_str):
    dsl_str = re.sub(LINGVO_TAG_EXPR, lingvo_to_html, dsl_str)
    return lxml.html.fromstring(dsl_str)

Добавьте случай elif для любых отсутствующих тегов. Конечно, вы также можете оставить теги в покое, вместо того, чтобы конвертировать их в <div> или <span>.

. Вызывая это следующим образом:

html = parse_lingvo("[tag]text [anothertag]an [']othertext[/'][/tag][/anothertag]")
print(lxml.html.tostring(html))

выводит для меня следующий HTML-код.

b'<tag>text <anothertag>an <span class="stressed">othertext</span></anothertag></tag>'

html - это lxml Element, поэтому доступны такие методы, как .xpath().

...