python: имя тега lxml xpath с двоеточием

мне нужно разобрать фид, но один из элементов (тег) имеет colon <dc:creator>leemore23</dc:creator>

как я могу разобрать его с помощью lxml? поэтому я сделал это таким образом

r = requests.get('http://www.site.com/feed/')
foo = (r.content).replace("dc:creator","dc")
tree = lxml.etree.fromstring(foo)
for article_node in tree.xpath('//item'):
    data['dc'] = article_node.xpath('.//dc')[0].text.strip()

но я думаю, что есть лучший способ, что-то вроде

data['dc'] = article_node.xpath('.//dc:creator')[0].text.strip()

or

data['dc'] = article_node.xpath('.//dc|creator')[0].text.strip()

так что без замены

что вы можете мне посоветовать?


person yital9    schedule 20.11.2012    source источник
comment
Я подозреваю, что вам следует взглянуть на feedparser библиотеку и не изобретать велосипед.   -  person Martijn Pieters    schedule 20.11.2012


Ответы (2)


Префикс dc: указывает на пространство имен XML. Используйте поддержку пространства имен API elementtree, чтобы справиться с этим, а не просто удалить его из ввода. Как это бывает, dc обычно относится к метаданным Dublin Core.

Вам нужно определить полный URL-адрес пространства имен, а затем использовать этот URL-адрес в своих запросах XPath:

DCNS = 'http://purl.org/dc/elements/1.1/'
creator = article_node.xpath('.//{{{0}}}creator'.format(DCNS))

Здесь я использовал рекомендуемый URL-адрес пространства имен http://purl.org/dc/elements/1.1/ для префикса ядра dublin.

Обычно вы можете определить URL-адрес из свойства .nsmap; ваш корневой элемент вероятно имеет следующий атрибут .nsmap:

{'dc': 'http://purl.org/dc/elements/1.1/'}

и, таким образом, вы можете изменить свой код на:

creator = article_node.xpath('.//{{{0}}}creator'.format(article_node.nsmap['dc']))

Это можно еще больше упростить, передав словарь nsmap методу xpath() в качестве ключевого слова namespaces, после чего вы можете использовать префикс в своем выражении xpath:

creator = article_node.xpath('.//dc:creator', namespaces=article_node.nsmap)
person Martijn Pieters    schedule 20.11.2012
comment
он работает с пространствами имен, но есть проблема. тег (dc:creator) имеет текст cdata, он не анализируется.. если там простой текст, то все ок, а с cdata не работает. Есть идеи? - person yital9; 20.11.2012
comment
@yital9: Как вы получаете доступ к текстовому содержимому тега? LXML обычно удаляет "оболочку" CDATA при использовании обычных API. - person Martijn Pieters; 20.11.2012
comment
если есть простой текст (без cdata) article_node.xpath('.//dc:creator', namespaces = dc)[0].text.strip() возвращает текст, но если есть cdata article_node.xpath('./ /dc:creator', namespaces = dc) возвращает [] и article_node.xpath('.//dc:creator', namespaces = dc)[0].text.strip() вызывает исключение. - person yital9; 20.11.2012
comment
@ yital9: Можете ли вы привести пример ввода? - person Martijn Pieters; 20.11.2012
comment
конечно, goptionsblog.com/feed здесь: ‹dc:creator› анализируется с пространствами имен OK, но ‹content:encoded› нет.. - person yital9; 20.11.2012
comment
@yital9: это другое пространство имен. Вам нужно использовать правильный префикс; article_node.xpath('.//content:encoded', namespaces=article_node.nsmap) возвращает значение. Когда вы получаете исключение, проверьте, действительно ли ваш код нашел какие-либо элементы. - person Martijn Pieters; 20.11.2012
comment
@ yital9: Почему вы пытаетесь самостоятельно анализировать потоки атомов, когда feedparser уже отлично с этим справляется, кстати? - person Martijn Pieters; 20.11.2012

dc: указывает на пространство имен. При использовании метода xpath из lxml используйте параметр namespaces для поиска элементов в пространстве имен. .

Итак, в вашем случае, используя префикс ядра дублина, предоставленный @MartijnPieters,

r = requests.get('http://www.site.com/feed/')
tree = lxml.etree.fromstring(r.content)
ns = {'dc':'http://purl.org/dc/elements/1.1/'}
for article_node in tree.xpath('//item'):
    data['dc'] = article_node.xpath('.//dc:creator', namespaces = ns)[0].text.strip()
person unutbu    schedule 20.11.2012
comment
это работает, большое спасибо! но есть проблема, тэг (dc:creator) имеет текст cdata, он не анализируется.. если там простой текст, то все ок, а с cdata не работает.. - person yital9; 20.11.2012