Ottieni il valore dell'elemento con minidom con Python


109

Sto creando un frontend GUI per l'API Eve Online in Python.

Ho estratto con successo i dati XML dal loro server.

Sto cercando di prendere il valore da un nodo chiamato "nome":

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

Questo sembra trovare il nodo, ma l'output è di seguito:

[<DOM Element: name at 0x11e6d28>]

Come posso fare in modo che stampi il valore del nodo?


5
Sta iniziando a sembrare che la risposta alla maggior parte delle domande "minidom" sia "usa ElementTree".
Warren P

Risposte:


156

Dovrebbe solo essere

name[0].firstChild.nodeValue

4
Quando faccio il nome [0] .nodeValue restituisce "Nessuno", solo per testarlo ho passato il nome [0] .nodeName e mi ha dato "nome" che è corretto. Qualche idea?
RailsSon

28
E il nome [0] .firstChild.nodeValue?
eduffy il

7
Fai solo attenzione che non ti affidi ai dettagli di implementazione nel generatore xml. Non ci sono garanzie che il primo figlio sia il nodo di testo né l' unico nodo di testo in tutti i casi in cui può esserci più di un nodo figlio.
Henrik Gustafsson

53
Perché qualcuno dovrebbe progettare una libreria in cui il nodeValue di <name> Smith </name> è tutt'altro che "Smith" ?! Quella piccola pepita mi è costata 30 minuti per strapparmi i capelli. Adesso sono calvo. Grazie, minidom.
Assaf Lavie

10
È solo per il modo in cui l'hanno progettato per funzionare con html, per consentire elementi come questo <nodeA> Some Text <nodeinthemiddle> __complex__structure__ </nodeinthemiddle> Un po 'di testo </nodeA>, in questo caso pensi che il nodeValue di nodeA dovrebbe contenere tutto il testo inclusa la struttura complessa, o semplicemente 2 nodi di testo e il nodo centrale. Non è il modo più carino di vederlo, ma posso capire perché lo hanno fatto.
Josh Mc

60

Probabilmente qualcosa del genere se è la parte di testo che vuoi ...

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)

La parte testuale di un nodo è considerata un nodo a sé stante posto come nodo figlio di quello che hai richiesto. Quindi dovrai esaminare tutti i suoi figli e trovare tutti i nodi figli che sono nodi di testo. Un nodo può avere diversi nodi di testo; per esempio.

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

Vuoi sia "blabla" che "znylpx"; da qui il "" .join (). Potresti voler sostituire lo spazio con una nuova riga o giù di lì, o forse con niente.


12

puoi usare qualcosa del genere, ha funzionato per me

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

So che questa domanda è piuttosto vecchia ora, ma ho pensato che potresti avere un tempo più facile con 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

So che non è molto specifico, ma l'ho appena scoperto, e finora è molto più facile farmi girare la testa rispetto al minidom (poiché così tanti nodi sono essenzialmente spazi bianchi).

Ad esempio, hai il nome del tag e il testo effettivo insieme, proprio come probabilmente ti aspetteresti:

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

8

La risposta di cui sopra è corretta, vale a dire:

name[0].firstChild.nodeValue

Tuttavia per me, come altri, il mio valore era più in basso nell'albero:

name[0].firstChild.firstChild.nodeValue

Per trovarlo ho usato quanto segue:

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 )

L'esecuzione di questo per il mio semplice file SVG creato con Inkscape mi ha dato:

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: ()

Ho usato xml.dom.minidom, i vari campi sono spiegati in questa pagina, MiniDom Python.


2

Ho avuto un caso simile, quello che ha funzionato per me è stato:

name.firstChild.childNodes [0] .data

XML dovrebbe essere semplice e lo è davvero e non so perché il minidom di Python lo abbia fatto così complicato ... ma è così che è fatto


2

Ecco una risposta leggermente modificata di Henrik per più nodi (cioè quando getElementsByTagName restituisce più di un'istanza)

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

2

Alla domanda è stata data risposta, il mio contributo consiste nel chiarire una cosa che può confondere i principianti:

Alcune delle risposte suggerite e corrette utilizzate firstChild.datae altre firstChild.nodeValueinvece utilizzate . Nel caso ti stia chiedendo qual è la differenza tra loro, dovresti ricordare che fanno la stessa cosa perché nodeValueè solo un alias per data.

Il riferimento alla mia dichiarazione può essere trovato come commento sul codice sorgente di minidom :

# nodeValueè un alias perdata


0

È un albero e potrebbero esserci elementi annidati. Provare:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.