Разбор XML (musicbrainz) в Python

Я пытаюсь импортировать URL-адреса, подобные этому (http://musicbrainz.org/ws/2/artist/72c536dc-7137-4477-a521-567eeb840fa8) в python и извлеките значение «gender».

import urllib2
import codecs
import sys
import os
from xml.dom import minidom
import xml.etree.cElementTree as ET

#urlbob = urllib2.urlopen('http://musicbrainz.org/ws/2/artist/72c536dc-7137-4477-a521-567eeb840fa8')
url = 'dylan.xml'

#attempt 1 - using minidom
xmldoc = minidom.parse(url)
itemlist = xmldoc.getElementsByTagName('artist') 

#attempt 2 - using ET
tree = ET.parse('dylan.xml')
root = tree.getroot()

for child in root:
    print child.tag, child.attrib 

Кажется, я не могу определить пол ни с помощью мини-дома, ни с помощью э-дерева. В текущем виде скрипт возвращает

{http://musicbrainz.org/ns/mmd-2.0#}artist {'type': 'Person', 'id': '72c536dc-7137-4477-a521-567eeb840fa8'}

person Nicholas Rogers    schedule 16.11.2014    source источник


Ответы (2)


Это потому, что вы зацикливаете root, который является только корнем дерева, имеет ли это смысл? Когда вы зацикливаете корень, он возвращает только следующего потомка и останавливается на этом.

Вам нужно зациклить итерацию, чтобы она возвращала следующий узел и получала результат, см. это:

tree = ET.parse('dylan.xml')
root = tree.getroot()

# loop the root iterable which will keep returning next node
for node in root.iter(): # or root.getiterator() if < Python 2.7
    print node.tag, node.attrib, node.text

Полученные результаты:

{http://musicbrainz.org/ns/mmd-2.0#}metadata {} None
{http://musicbrainz.org/ns/mmd-2.0#}artist {'type': 'Person', 'id': '72c536dc-7137-4477-a521-567eeb840fa8'} None
{http://musicbrainz.org/ns/mmd-2.0#}name {} Bob Dylan
{http://musicbrainz.org/ns/mmd-2.0#}sort-name {} Dylan, Bob
{http://musicbrainz.org/ns/mmd-2.0#}ipi {} 00008955074
{http://musicbrainz.org/ns/mmd-2.0#}ipi-list {} None
{http://musicbrainz.org/ns/mmd-2.0#}ipi {} 00008955074
{http://musicbrainz.org/ns/mmd-2.0#}ipi {} 00008955172
{http://musicbrainz.org/ns/mmd-2.0#}isni-list {} None
{http://musicbrainz.org/ns/mmd-2.0#}isni {} 0000000121479733
{http://musicbrainz.org/ns/mmd-2.0#}gender {} Male
{http://musicbrainz.org/ns/mmd-2.0#}country {} US
{http://musicbrainz.org/ns/mmd-2.0#}area {'id': '489ce91b-6658-3307-9877-795b68554c98'} None
{http://musicbrainz.org/ns/mmd-2.0#}name {} United States
{http://musicbrainz.org/ns/mmd-2.0#}sort-name {} United States
{http://musicbrainz.org/ns/mmd-2.0#}iso-3166-1-code-list {} None
{http://musicbrainz.org/ns/mmd-2.0#}iso-3166-1-code {} US
{http://musicbrainz.org/ns/mmd-2.0#}begin-area {'id': '04e60741-b1ae-4078-80bb-ffe8ae643ea7'} None
{http://musicbrainz.org/ns/mmd-2.0#}name {} Duluth
{http://musicbrainz.org/ns/mmd-2.0#}sort-name {} Duluth
{http://musicbrainz.org/ns/mmd-2.0#}life-span {} None
{http://musicbrainz.org/ns/mmd-2.0#}begin {} 1941-05-24
person Anzel    schedule 16.11.2014
comment
для меня это возвращает: для узла в root.iter(): AttributeError: iter - person Nicholas Rogers; 17.11.2014
comment
@NicholasRogers, у вас есть import xml.etree.cElementTree as ET и root=tree.getroot()? - person Anzel; 17.11.2014
comment
для узла в root.findall('.//*'): print node.tag, node.attrib, node.text делает свое дело - person Nicholas Rogers; 17.11.2014
comment
@NicholasRogers, интересно, возможно, разные версии в xml? - person Anzel; 17.11.2014
comment
в любом случае, пока вы понимаете, что вам нужно зацикливать детей root, а не себя :) рад, что вы отсортированы - person Anzel; 17.11.2014
comment
@NicholasRogers, ваш Python, вероятно, ‹ 2.7? попробуйте root.getiterator(), я просто проверяю, что документ iter() является новым в версии 2.7, тогда как getiterator устарел - person Anzel; 17.11.2014

## This prints out the tree as the xml lib sees it 
## (I found it made debugging a little easier)
#def print_xml(node, depth = 0):
#    for child in node:
#        print "\t"*depth + str(child)
#        print_xml(child, depth = depth + 1)
#print_xml(root)

# attempt 1
xmldoc = minidom.parse(url)
genders = xmldoc.getElementsByTagName('gender') # <== you want gender not artist
for gender in genders:
    print gender.firstChild.nodeValue

# attempt 2
ns = "{http://musicbrainz.org/ns/mmd-2.0#}"
xlpath = "./" + ns + "artist/" + ns + "gender"
genders = root.findall(xlpath) # <== xpath was made for this..
for gender in genders:
    print gender.text

Итак... проблема с вашей первой попыткой заключается в том, что вы просматриваете список всех элементов исполнителя, а не гендерных элементов (дочерний элемент единственного элемента исполнителя в списке).

Проблема с вашей второй попыткой заключается в том, что вы просматриваете список дочерних элементов корневого элемента (который представляет собой список, содержащий один элемент метаданных).

Базовая структура:

<artist>
    <name>
    <sort-name>
    <ipi>
    <ipi-list>
        <ipi>
        <ipi>
    <isni-list>
        <isni>
    <gender>
    <country>
    <area>
        <name>
        <sort-name>
        <iso-3166-1-code-list>
            <iso-3166-1-code>
    <begin-area>
        <name>
        <sort-name>
    <life-span>
        <begin>

поэтому вам нужно получить root -> artist -> пол или просто найти узел, который вам действительно нужен (пол в данном случае).

person demented hedgehog    schedule 17.11.2014