Obtenga el valor del elemento con minidom con Python

109

Estoy creando una interfaz gráfica de usuario para la API de Eve Online en Python.

He extraído con éxito los datos XML de su servidor.

Estoy tratando de tomar el valor de un nodo llamado "nombre":

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

Esto parece encontrar el nodo, pero el resultado es el siguiente:

[<DOM Element: name at 0x11e6d28>]

¿Cómo puedo hacer que imprima el valor del nodo?

RailsSon
fuente
5
Está empezando a parecer que la respuesta a la mayoría de las preguntas de "minidom" es "use ElementTree".
Warren P

Respuestas:

156

Debería ser

name[0].firstChild.nodeValue
eduffy
fuente
4
Cuando hago el nombre [0] .nodeValue devuelve "Ninguno", solo para probar le pasé el nombre [0] .nodeName y me dio "nombre", que es correcto. ¿Algunas ideas?
RailsSon
28
¿Qué pasa con el nombre [0] .firstChild.nodeValue?
eduffy
7
Solo tenga en cuenta que no depende de los detalles de implementación en el generador xml. No hay garantías de que el primer hijo sea el nodo de texto ni el único nodo de texto en los casos en los que puede haber más de un nodo hijo.
Henrik Gustafsson
53
¿Por qué alguien diseñaría una biblioteca en la que el nodeValue de <name> Smith </name> sea cualquier cosa menos "Smith"? Esa pequeña pepita me costó 30 minutos arrancarme el pelo. Ahora soy calvo. Gracias, minidom.
Assaf Lavie
10
Es solo por la forma en que lo diseñaron para que funcione con html, para permitir elementos como este <nodeA> Algún texto <nodeinthemiddle> __complex__structure__ </nodeinthemiddle> Un poco más de texto </nodeA>, en este caso, ¿cree que nodeA's nodeValue debe contener todo el texto, incluida la estructura compleja, o simplemente 2 nodos de texto y el nodo del medio. No es la mejor manera de verlo, pero puedo ver por qué lo hicieron.
Josh Mc
60

Probablemente algo como esto si es la parte de texto que desea ...

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 de texto de un nodo se considera un nodo en sí mismo colocado como un nodo hijo del que solicitó. Por lo tanto, querrá revisar todos sus elementos secundarios y encontrar todos los nodos secundarios que sean nodos de texto. Un nodo puede tener varios nodos de texto; p.ej.

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

Quieres tanto 'blabla' como 'znylpx'; de ahí el "" .join (). Es posible que desee reemplazar el espacio con una nueva línea o algo así, o tal vez con nada.

Henrik Gustafsson
fuente
12

puedes usar algo como esto, funcionó para mí

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
samaksh
fuente
8

Sé que esta pregunta es bastante antigua ahora, pero pensé que podría ser más fácil 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

Sé que no es muy específico, pero lo acabo de descubrir, y hasta ahora es mucho más fácil entender que el minidom (ya que muchos nodos son esencialmente espacios en blanco).

Por ejemplo, tiene el nombre de la etiqueta y el texto real juntos, tal como probablemente esperaría:

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

La respuesta anterior es correcta, a saber:

name[0].firstChild.nodeValue

Sin embargo, para mí, como otros, mi valor estaba más abajo en el árbol:

name[0].firstChild.firstChild.nodeValue

Para encontrar esto utilicé lo siguiente:

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 )

Ejecutando esto para mi archivo SVG simple creado con Inkscape, esto me dio:

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

Usé xml.dom.minidom, los distintos campos se explican en esta página, MiniDom Python.

LazyBrush
fuente
2

Tuve un caso similar, lo que funcionó para mí fue:

name.firstChild.childNodes [0] .data

Se supone que XML es simple y realmente lo es y no sé por qué el minidom de Python lo hizo tan complicado ... pero así es como se hace

Robertzp
fuente
2

Aquí hay una respuesta ligeramente modificada de Henrik para múltiples nodos (es decir, cuando getElementsByTagName devuelve más de una instancia)

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

La pregunta ha sido respondida, mi aporte consiste en aclarar una cosa que puede confundir a los principiantes:

Algunas de las respuestas sugeridas y correctas se utilizaron firstChild.datay otras se utilizaron en su firstChild.nodeValuelugar. En caso de que se pregunte cuál es la diferencia entre ellos, debe recordar que hacen lo mismo porque nodeValuees solo un alias paradata .

La referencia a mi declaración se puede encontrar como un comentario sobre el código fuente de minidom :

# nodeValuees un alias paradata

Billal Begueradj
fuente
0

Es un árbol y puede haber elementos anidados. Tratar:

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
TextGeek
fuente