Python + lxml: как найти пространство имен тега?

Я обрабатываю некоторые файлы HTML с помощью python + lxml. Некоторые из них были отредактированы с помощью MS Word, и у нас есть теги <p>, например, записанные как <o:p>&nbsp</o:p>. IE и Firefox не интерпретируют эти теги MS как настоящие теги <p> и не отображают разрывы строк до и после тегов <o:p>, и именно так исходные редакторы отформатировали файлы, например. без пробелов вокруг nbsp.

lxml, с другой стороны, аккуратен, и после обработки файлов HTML мы видим, что все теги <o:p> были изменены на правильные теги <p>. К сожалению, после этой очистки оба браузера теперь отображают разрывы строк вокруг всех nbsp, что нарушает исходное форматирование.

Итак, моя идея состояла в том, чтобы просмотреть все эти теги <o:p> и либо удалить их, либо добавить их атрибут .text к родительскому атрибуту .text, то есть удалить маркеры тега <o:p>.

from lxml import etree
import lxml.html
from StringIO import StringIO

s='<p>somepara</p> <o:p>msoffice_para</o:p>'

parser = lxml.html.HTMLParser()
html=lxml.html.parse( StringIO( s), parser)

for t in html.xpath( "//p"):
     print "tag: " + t.tag + ",  text: '" + t.text + "'"

Результат:

tag: p,  text: 'somepara'
tag: p,  text: 'msoffice_para'

Таким образом, lxlm удаляет имя пространства имен из маркера тега. Есть ли способ узнать, какой тег <p> из какого пространства имен, поэтому я удаляю только теги с <o:p>?

Спасибо.


person user928989    schedule 05.09.2011    source источник


Ответы (2)


Из спецификаций HTML: "Синтаксис HTML не поддерживает объявления пространств имен" . Поэтому я думаю, что lxml.html.HTMLParser удаляет/игнорирует пространство имен.

Однако BeautifulSoup по-разному анализирует HTML, поэтому я подумал, что стоит попробовать. Если у вас также установлен BeautifulSoup, вы можете использовать парсер BeautifulSoup с lxml следующим образом:

import lxml.html.soupparser as soupparser
import lxml.html
import io
s='<p>somepara</p> <o:p>msoffice_para</o:p>'
html=soupparser.parse(io.BytesIO(s)) 

BeautifulSoup не удаляет пространство имен, но и не распознает его как таковое. Вместо этого это просто часть имени тега.

То есть,

html.xpath('//o:p',namespaces={'o':'foo'})

не работает. Но этот обходной путь/хак

for t in html.xpath('//*[name()="o:p"]'):    
    print "tag: " + t.tag + ",  text: '" + t.text + "'"

урожаи

tag: o:p,  text: 'msoffice_para'
person unutbu    schedule 05.09.2011

Если html на самом деле правильно сформирован, вместо этого вы можете использовать etree.XMLParser. В противном случае попробуйте ответ unutbu.

person Steven    schedule 05.09.2011