Uzyskaj wartość elementu za pomocą minidom w Pythonie


109

Tworzę nakładkę GUI dla Eve Online API w Pythonie.

Udało mi się pobrać dane XML z ich serwera.

Próbuję pobrać wartość z węzła o nazwie „nazwa”:

from xml.dom.minidom import parse
dom = parse("C:\\eve.xml")
name = dom.getElementsByTagName('name')
print name

Wydaje się, że znajduje się węzeł, ale wynik jest poniżej:

[<DOM Element: name at 0x11e6d28>]

Jak mogę to zrobić, aby wydrukować wartość węzła?


5
Zaczyna się wydawać, że odpowiedzią na większość pytań „minidom” jest „użyj ElementTree”.
Warren P

Odpowiedzi:


156

Po prostu powinno być

name[0].firstChild.nodeValue

4
Kiedy nazwa [0] .nodeValue zwraca "Brak", aby przetestować, przeszedłem nazwę [0] .nodeName i dało mi to "imię", które jest poprawne. Jakieś pomysły?
RailsSon

28
A co z nazwą [0] .firstChild.nodeValue?
eduffy

7
Uważaj tylko, że nie polegasz na szczegółach implementacji w generatorze xml. Nie ma żadnych gwarancji, że pierwsze dziecko jest węzeł tekstu, ani tylko węzeł tekst we wszelkich sprawach, gdzie może być więcej niż jeden węzeł dziecko.
Henrik Gustafsson

53
Dlaczego ktoś miałby projektować bibliotekę, w której wartość nodeValue <name> Smith </name> jest inna niż „Smith” ?! Ten mały samorodek kosztował mnie 30 minut wyrywania włosów. Jestem teraz łysy. Dzięki, minidom.
Assaf Lavie

10
To tylko ze względu na sposób, w jaki zaprojektowali go do pracy z html, aby umożliwić takie elementy jak <nodeA> Some Text <nodeinthemiddle> __complex__structure__ </nodeinthemiddle> Trochę więcej tekstu </nodeA>, w tym przypadku myślisz, że nodeA's nodeValue powinien zawierać cały tekst, łącznie ze złożoną strukturą lub po prostu 2 węzły tekstowe i środkowy. Nie jest to najprzyjemniejszy sposób patrzenia na to, ale rozumiem, dlaczego to zrobili.
Josh Mc,

60

Prawdopodobnie coś takiego, jeśli jest to część tekstowa, którą chcesz ...

from xml.dom.minidom import parse
dom = parse("C:\\eve.xml")
name = dom.getElementsByTagName('name')

print " ".join(t.nodeValue for t in name[0].childNodes if t.nodeType == t.TEXT_NODE)

Część tekstowa węzła jest uważana za węzeł sam w sobie umieszczony jako węzeł potomny tego, o który prosiłeś. Dlatego będziesz chciał przejrzeć wszystkie jego elementy podrzędne i znaleźć wszystkie węzły potomne, które są węzłami tekstowymi. Węzeł może mieć kilka węzłów tekstowych; na przykład.

<name>
  blabla
  <somestuff>asdf</somestuff>
  znylpx
</name>

Chcesz zarówno „blabla”, jak i „znylpx”; stąd „” .join (). Możesz chcieć zastąpić spację znakiem nowej linii lub czymś takim, a może nic.


12

możesz użyć czegoś takiego, ale mi się udało

doc = parse('C:\\eve.xml')
my_node_list = doc.getElementsByTagName("name")
my_n_node = my_node_list[0]
my_child = my_n_node.firstChild
my_text = my_child.data 
print my_text

8

Wiem, że to pytanie jest teraz dość stare, ale pomyślałem, że możesz mieć łatwiejszy czas z ElementTree

from xml.etree import ElementTree as ET
import datetime

f = ET.XML(data)

for element in f:
    if element.tag == "currentTime":
        # Handle time data was pulled
        currentTime = datetime.datetime.strptime(element.text, "%Y-%m-%d %H:%M:%S")
    if element.tag == "cachedUntil":
        # Handle time until next allowed update
        cachedUntil = datetime.datetime.strptime(element.text, "%Y-%m-%d %H:%M:%S")
    if element.tag == "result":
        # Process list of skills
        pass

Wiem, że to nie jest super specyficzne, ale właśnie to odkryłem i jak dotąd znacznie łatwiej jest mi się rozejrzeć niż minidom (ponieważ tak wiele węzłów to w zasadzie białe spacje).

Na przykład masz razem nazwę tagu i rzeczywisty tekst, tak jak można się spodziewać:

>>> element[0]
<Element currentTime at 40984d0>
>>> element[0].tag
'currentTime'
>>> element[0].text
'2010-04-12 02:45:45'e

8

Powyższa odpowiedź jest poprawna, a mianowicie:

name[0].firstChild.nodeValue

Jednak dla mnie, podobnie jak innych, moja wartość była niższa w hierarchii:

name[0].firstChild.firstChild.nodeValue

Aby to znaleźć, użyłem:

def scandown( elements, indent ):
    for el in elements:
        print("   " * indent + "nodeName: " + str(el.nodeName) )
        print("   " * indent + "nodeValue: " + str(el.nodeValue) )
        print("   " * indent + "childNodes: " + str(el.childNodes) )
        scandown(el.childNodes, indent + 1)

scandown( doc.getElementsByTagName('text'), 0 )

Uruchomienie tego dla mojego prostego pliku SVG utworzonego w Inkscape dało mi:

nodeName: text
nodeValue: None
childNodes: [<DOM Element: tspan at 0x10392c6d0>]
   nodeName: tspan
   nodeValue: None
   childNodes: [<DOM Text node "'MY STRING'">]
      nodeName: #text
      nodeValue: MY STRING
      childNodes: ()
nodeName: text
nodeValue: None
childNodes: [<DOM Element: tspan at 0x10392c800>]
   nodeName: tspan
   nodeValue: None
   childNodes: [<DOM Text node "'MY WORDS'">]
      nodeName: #text
      nodeValue: MY WORDS
      childNodes: ()

Użyłem xml.dom.minidom, różne pola są wyjaśnione na tej stronie, MiniDom Python.


2

Miałem podobny przypadek, co działało u mnie to:

name.firstChild.childNodes [0] .data

XML ma być prosty i tak naprawdę jest i nie wiem, dlaczego minidom Pythona zrobił to tak skomplikowane ... ale tak to jest zrobione


2

Oto nieco zmodyfikowana odpowiedź Henrika dla wielu węzłów (np. Gdy getElementsByTagName zwraca więcej niż jedną instancję)

images = xml.getElementsByTagName("imageUrl")
for i in images:
    print " ".join(t.nodeValue for t in i.childNodes if t.nodeType == t.TEXT_NODE)

2

Odpowiedź została udzielona, ​​mój wkład polega na wyjaśnieniu jednej rzeczy, która może zmylić początkujących:

Zastosowano niektóre z sugerowanych i poprawnych odpowiedzi, firstChild.dataa inne firstChild.nodeValuezamiast. Jeśli zastanawiasz się, jaka jest różnica między nimi, powinieneś pamiętać, że robią to samo, ponieważ nodeValuejest to tylko alias dla data.

Odniesienie do mojego oświadczenia można znaleźć jako komentarz do kodu źródłowego minidom :

# nodeValuejest aliasem dladata


0

To drzewo i mogą zawierać elementy zagnieżdżone. Próbować:

def innerText(self, sep=''):
    t = ""
    for curNode in self.childNodes:
        if (curNode.nodeType == Node.TEXT_NODE):
            t += sep + curNode.nodeValue
        elif (curNode.nodeType == Node.ELEMENT_NODE):
            t += sep + curNode.innerText(sep=sep)
    return t
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.