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?


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

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.


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

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

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.


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


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)

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


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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.