Исправление tostring () в lxml Python - PullRequest
6 голосов
/ 06 января 2011
Функция

lxml tostring() выглядит совершенно неработоспособной при печати только частей документов. Свидетель:

from lxml.html import fragment_fromstring, tostring
frag = fragment_fromstring('<p>This stuff is <em>really</em> great!')
em = frag.cssselect('em').pop(0)
print tostring(em)

Я ожидаю <em>really</em>, но вместо этого он печатает <em>really</em> great!, что неправильно . Великий !' является не частью выбранного em. Это не только неправильно, это пилюля, по крайней мере, для обработки структурированного документа XML, где такой конечный текст будет обычным делом.

Насколько я понимаю, lxml хранит любой свободный текст, который идет после текущего элемента в атрибуте .tail элемента. Сканирование кода для tostring() приводит меня к функции _write() ElementTree.py, которая явно всегда печатает хвост. Это правильное поведение для целых деревьев, но не для последнего элемента при рендеринге поддерева, но оно не делает различий.

Чтобы получить правильное отображение без хвоста выбранного XML, я попытался написать функцию toxml() с нуля, чтобы использовать вместо нее. В основном это сработало, но есть много особых случаев при обработке комментариев, инструкций по обработке, пространств имен, кодировок, yadda yadda. Поэтому я поменял передачу и теперь просто копилкой tostring(), постобработав вывод, чтобы удалить оскорбительный текст .tail:

def toxml(e):
    """ Replacement for lxml's tostring() method that doesn't add spurious
    tail text. """

    from lxml.etree import tostring
    xml = tostring(e)
    if e.tail:
        xml = xml[:-len(e.tail)]
    return xml

Базовая серия тестов показывает, что это прекрасно работает.

Критика и / или предложения?

1 Ответ

12 голосов
/ 06 января 2011

Как насчет xml = lxml.etree.tostring(e, with_tail=False)?

from lxml.html import fragment_fromstring
from lxml.etree import tostring
frag = fragment_fromstring('<p>This stuff is <em>really</em> great!')
em = frag.cssselect('em').pop(0)
print tostring(em, with_tail=False)

Похоже, with_tail был добавлен в v2.0; у вас есть более старая версия?

...