Obtenir la valeur de l'élément avec minidom avec Python

109

Je crée une interface graphique pour l'API Eve Online en Python.

J'ai réussi à extraire les données XML de leur serveur.

J'essaie de saisir la valeur d'un nœud appelé "nom":

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

Cela semble trouver le nœud, mais la sortie est ci-dessous:

[<DOM Element: name at 0x11e6d28>]

Comment pourrais-je lui faire imprimer la valeur du nœud?

RailsSon
la source
5
Cela commence à ressembler à la réponse à la plupart des questions "minidom" est "utiliser ElementTree".
Warren P du

Réponses:

156

Ça devrait juste être

name[0].firstChild.nodeValue
Eduffy
la source
4
Quand je ne nomme [0] .nodeValue est redonne "Aucun", juste pour tester je lui ai passé le nom [0] .nodeName et il m'a donné "nom" qui est correct. Des idées?
Rails:
28
Qu'en est-il du nom [0] .firstChild.nodeValue?
eduffy
7
Gardez simplement à l'esprit que vous ne vous fiez pas aux détails d'implémentation dans le générateur xml. Il n'y a aucune garantie que le premier enfant soit le nœud de texte ni le seul nœud de texte dans tous les cas où il peut y avoir plus d'un nœud enfant.
Henrik Gustafsson
53
Pourquoi quelqu'un créerait-il une bibliothèque dans laquelle la valeur nodeValue de <name> Smith </name> serait autre chose que "Smith"?! Cette petite pépite m'a coûté 30 minutes à m'arracher les cheveux. Je suis chauve maintenant. Merci, minidom.
Assaf Lavie
10
C'est juste à cause de la façon dont ils l'ont conçu pour fonctionner avec html, pour permettre des éléments tels que ce <nodeA> Some Text <nodeinthemiddle> __complex__structure__ </nodeinthemiddle> Un peu plus de texte </nodeA>, dans ce cas pensez-vous que nodeA's nodeValue doit contenir tout le texte, y compris la structure complexe, ou simplement 2 nœuds de texte et le nœud du milieu. Ce n'est pas la meilleure façon de voir les choses, mais je peux voir pourquoi ils l'ont fait.
Josh Mc
60

Probablement quelque chose comme ça si c'est la partie de texte que vous voulez ...

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 partie texte d'un nœud est considérée comme un nœud en lui-même placé en tant que nœud enfant de celui que vous avez demandé. Ainsi, vous voudrez parcourir tous ses enfants et trouver tous les nœuds enfants qui sont des nœuds de texte. Un nœud peut avoir plusieurs nœuds de texte; par exemple.

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

Vous voulez à la fois «blabla» et «znylpx»; d'où le "" .join (). Vous voudrez peut-être remplacer l'espace par une nouvelle ligne ou plus, ou peut-être par rien.

Henrik Gustafsson
la source
12

vous pouvez utiliser quelque chose comme ça, ça a marché pour moi

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
la source
8

Je sais que cette question est assez ancienne maintenant, mais je pensais que vous auriez peut-être plus de facilité avec 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

Je sais que ce n'est pas très spécifique, mais je viens de le découvrir, et jusqu'à présent, il est beaucoup plus facile de se déplacer que le minidom (car tant de nœuds sont essentiellement des espaces blancs).

Par exemple, vous avez le nom de la balise et le texte réel ensemble, comme vous vous en doutez probablement:

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

La réponse ci-dessus est correcte, à savoir:

name[0].firstChild.nodeValue

Cependant pour moi, comme d'autres, ma valeur était plus bas dans l'arbre:

name[0].firstChild.firstChild.nodeValue

Pour trouver cela, j'ai utilisé ce qui suit:

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 )

Lancer ceci pour mon simple fichier SVG créé avec Inkscape, cela m'a donné:

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

J'ai utilisé xml.dom.minidom, les différents champs sont expliqués sur cette page, MiniDom Python.

LazyBrush
la source
2

J'ai eu un cas similaire, ce qui a fonctionné pour moi était:

name.firstChild.childNodes [0] .data

XML est censé être simple et c'est vraiment le cas et je ne sais pas pourquoi le minidom de python l'a fait si compliqué ... mais c'est comme ça que c'est fait

robertzp
la source
2

Voici une réponse légèrement modifiée de Henrik pour plusieurs nœuds (c'est-à-dire lorsque getElementsByTagName renvoie plus d'une instance)

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

La question a été répondue, ma contribution consiste à clarifier une chose qui peut dérouter les débutants:

Certaines des réponses suggérées et correctes utilisées firstChild.dataet d'autres utilisées à la firstChild.nodeValueplace. Au cas où vous vous demandez quelle est la différence entre eux, vous devez vous rappeler qu'ils font la même chose car nodeValuec'est juste un alias pour data.

La référence à ma déclaration peut être trouvée en tant que commentaire sur le code source de minidom :

# nodeValueest un alias pourdata

Billal Begueradj
la source
0

C'est un arbre et il peut y avoir des éléments imbriqués. Essayer:

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
la source