Теги lxml и <wbr>

По умолчанию lxml не понимает и тег wbr, используемый для добавления разрывов слов в длинных словах. Это форматирует это как <wbr></wbr> когда это должно быть отформатировано просто как <wbr>, похожий на тег br.

Как добавить это поведение в lxml?

4 ответа

Решение

На самом деле это не сложно исправить патч libxml2 (это пошаговое руководство было сделано на Ubuntu 11.04 с Python 2.7.3)

Сначала определите тестовую программу wbr_test.py:

from lxml import etree
from cStringIO import StringIO

wbr_html = """\
<html>
  <head>
    <title>wbr test</title>
  </head>
<body>
  Test for a breakable<wbr>word implemenation change
</body>
</html>
"""

parser = etree.HTMLParser()
tree   = etree.parse(StringIO(wbr_html), parser)

result = etree.tostring(tree.getroot(),
                         pretty_print=True, method="html")
if result.split() != wbr_html.split(): # split, as we are not interested in whitespace differences
    print(result)
    print("not ok")
else:
    print("OK")

Убедитесь, что он не работает, запустив python wbr_test.py, Следует вставить <\wbr> до <\body>и распечатать not ok в конце.

Скачать, распаковать и скомпилировать libxml2:

wget ftp://xmlsoft.org/libxml2/libxml2-2.8.0.tar.gz
tar xvf libxml2-2.8.0.tar.gz 
cd libxml2-2.8.0/
./configure --prefix=/usr
make -j8  # adjust number to match your number of cores

Установите и установите привязки python libxml2:

sudo make install
cd to_python_bindings
sudo python setup.py install

Проверьте свой wbr_test.py еще раз, чтобы убедиться, что это не с последней версией libxml2.

Сначала сделайте копию HTMLparser.c например, в /var/tmp,

Теперь отредактируйте файл HTMLparser.c на верхнем уровне источника libxml2. Поиск слова forced (только один случай). Вы будете на <br> определение тега. Скопируйте три строки, начиная с строки, которую вы только что нашли. Наиболее подходящая точка вставки - непосредственно перед концом (после определения <var>). Чтобы получить окончательную запятую прямо в таблице, вставьте три строки перед той, в которой просто '}' не тот, с '};',

Во вновь вставленный код заменить br с wbr и изменить DECL clear_attrs в NULL (при условии, что новый тег не имеет устаревших атрибутов).

Результат должен отличаться от версии в /var/tmp (diff -u HTMLparser.c /var/tmp) следующее:

@@ -1039,6 +1039,9 @@
 },
 { "var",   0, 0, 0, 0, 0, 0, 1, "instance of a variable or program argument",
DECL html_inline, NULL, DECL html_attrs, NULL, NULL
+},
+{ "wbr",   0, 2, 2, 1, 0, 0, 1, "possible line break ",
+   EMPTY , NULL , DECL core_attrs, NULL , NULL
 }
 };

Сделайте и установите:

make && sudo make install

Проверьте свой wbr_test.py еще раз. Должен показать OK

Хорошие новости! Это абсолютно невозможно. Имена тегов HTML запекаются прямо вlibxml2,

А также lxml.html.html5parser содержит пару серьезных ошибок, исправления которых еще не вошли в релиз.

Но, чёрт возьми, давайте исправим их локально и посмотрим, что получится.

>>> lxml.html.tostring(lxml.html.html5parser.fromstring('<p>hello<wbr>world!</p>'), encoding=unicode)
u'<html:p xmlns:html="http://www.w3.org/1999/xhtml">hello<html:wbr></html:wbr>world!</html:p>'

Так близко и в то же время так далеко. Структура правильная, по крайней мере.

Еще один раз:

>>> lxml.html.tostring(lxml.html.html5parser.fromstring('<p>hello<wbr>world!</p>', parser=lxml.html.html5parser.HTMLParser(namespaceHTMLElements=False)), encoding=unicode)
u'<p>hello<wbr></wbr>world!</p>'

Welp.

По крайней мере, это не так.

Я думаю, что я мог бы подать некоторые ошибки в lxml и libxml2.

Поскольку <wbr> существует только в HTML5, я подозреваю, что правильно сделать, это использовать lxml.html.html5parser,

Если не считать этого, список пустых тегов определен в обычном коде Python, так что вы всегда можете просто установить его; см. lxml.html.defs.empty_tags. Патчи приветствуются, я уверен.:)

Как быстро исправить, почему бы не использовать replace метод строк для удаления тегов закрытия?

>>> t = 'Thisisa<wbr></wbr>test'
>>> t.replace('</wbr>', '')
'Thisisa<wbr>test'
Другие вопросы по тегам