2013-08-05 3 views
6

Я пытаюсь открыть xml-файл и получить значения из определенных тегов. Я сделал это много, но этот конкретный xml дает мне некоторые проблемы. Вот раздел файла XML:xmlns namespace break lxml

<?xml version='1.0' encoding='UTF-8'?> 
<package xmlns="http://apple.com/itunes/importer" version="film4.7"> 
    <provider>filmgroup</provider> 
    <language>en-GB</language> 
    <actor name="John Smith" display="Doe John"</actor> 
</package> 

А вот пример моего кода Python:

metadata = '/Users/mylaptop/Desktop/Python/metadata.xml' 
from lxml import etree 
parser = etree.XMLParser(remove_blank_text=True) 
open(metadata) 
tree = etree.parse(metadata, parser) 
root = tree.getroot() 
for element in root.iter(tag='provider'): 
    providerValue = tree.find('//provider') 
    providerValue = providerValue.text 
    print providerValue 
tree.write('/Users/mylaptop/Desktop/Python/metadataDone.xml', pretty_print = True, xml_declaration = True, encoding = 'UTF-8') 

При запуске этого он не может найти тег поставщика или его стоимость. Если я удалю xmlns="http://apple.com/itunes/importer", тогда все будет работать как ожидалось. Мой вопрос в том, как удалить это пространство имен, поскольку меня это совсем не интересует, поэтому я могу получить значения тегов, которые мне нужны, используя lxml?

ответ

9

provider тег в http://apple.com/itunes/importer пространстве имен, поэтому вам необходимо либо использовать полное имя

{http://apple.com/itunes/importer}provider 

или использовать один из методов LXML, который имеет the namespaces parameter, такие как root.xpath. После этого вы можете указать его префикс пространства имен (например, ns:provider):

from lxml import etree 
parser = etree.XMLParser(remove_blank_text=True) 
tree = etree.parse(metadata, parser) 
root = tree.getroot() 
namespaces = {'ns':'http://apple.com/itunes/importer'} 
items = iter(root.xpath('//ns:provider/text()|//ns:actor/@name', 
         namespaces=namespaces)) 
for provider, actor in zip(*[items]*2): 
    print(provider, actor) 

дает

('filmgroup', 'John Smith') 

Обратите внимание, что XPath используется выше, предполагает, что <provider> и <actor> элементы всегда появляются в чередовании. Если это не так, то есть, конечно, способов обработки, но код становится немного более многословен:

for package in root.xpath('//ns:package', namespaces=namespaces): 
    for provider in package.xpath('ns:provider', namespaces=namespaces): 
     providerValue = provider.text 
     print providerValue 
    for actor in package.xpath('ns:actor', namespaces=namespaces): 
     print actor.attrib['name'] 
+0

Thats отлично убунт, работает удовольствие, веселит. – speedyrazor

+0

ubuntu, как бы я нашел атрибут тега, я внес свой первоначальный пример, поэтому я ищу значение имени актера = – speedyrazor

+0

Если у вас есть 'element', вы можете получить доступ к значению атрибута с помощью элемента .attrib [ 'имя'] '. Однако, если вы очищаете элементы 'provider' и' actor' из файла XML, вы можете настроить один XPath, чтобы сделать это одновременно, используя синтаксис '|' (или). Я редактировал сообщение, чтобы показать, что я имею в виду. – unutbu

1

Мое предложение не игнорировать пространства имен, но, вместо того, чтобы принять его во внимание. Я написал некоторые связанные функции (скопированные с небольшими изменениями) для моей работы в библиотеке django-quickbooks. С помощью этих функций, вы должны быть в состоянии сделать это:

providers = getels(root, 'provider', ns='http://apple.com/itunes/importer') 

Вот эти функции:

def get_tag_with_ns(tag_name, ns): 
    return '{%s}%s' % (ns, tag_name) 

def getel(elt, tag_name, ns=None): 
    """ Gets the first tag that matches the specified tag_name taking into 
    account the QB namespace. 

    :param ns: The namespace to use if not using the default one for 
    django-quickbooks. 
    :type ns: string 
    """ 

    res = elt.find(get_tag_with_ns(tag_name, ns=ns)) 
    if res is None: 
     raise TagNotFound('Could not find tag by name "%s"' % tag_name) 
    return res 

def getels(elt, *path, **kwargs): 
    """ Gets the first set of elements found at the specified path. 

    Example: 
     >>> xml = (
     "<root>" + 
      "<item>" + 
       "<id>1</id>" + 
      "</item>" + 
      "<item>" + 
       "<id>2</id>"* + 
      "</item>" + 
     "</root>") 
     >>> el = etree.fromstring(xml) 
     >>> getels(el, 'root', 'item', ns='correct/namespace') 
     [<Element item>, <Element item>] 
    """ 

    ns = kwargs['ns'] 

    i=-1 
    for i in range(len(path)-1): 
     elt = getel(elt, path[i], ns=ns) 
    tag_name = path[i+1] 
    return elt.findall(get_tag_with_ns(tag_name, ns=ns)) 
Смежные вопросы