Теги 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'