Python + lxml: как найти пространство имен тега? - PullRequest
2 голосов
/ 05 сентября 2011

Я обрабатываю некоторые 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>?

Спасибо.

Ответы [ 2 ]

1 голос
/ 05 сентября 2011

Из спецификации 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'
0 голосов
/ 06 сентября 2011

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

...