Получите значение элемента с помощью minidom с помощью Python


109

Я создаю интерфейс GUI для Eve Online API на Python.

Я успешно извлек XML-данные с их сервера.

Я пытаюсь получить значение из узла с именем «имя»:

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

Кажется, он находит узел, но результат ниже:

[<DOM Element: name at 0x11e6d28>]

Как я могу заставить его распечатать значение узла?


5
Начинает казаться, что ответ на большинство вопросов «минидома» - «используйте ElementTree».
Warren P

Ответы:


156

Это должно быть просто

name[0].firstChild.nodeValue

4
Когда я делаю name [0] .nodeValue, возвращается «None», просто для проверки я передал ему name [0] .nodeName, и он дал мне правильное «name». Любые идеи?
RailsSon

28
А как насчет name [0] .firstChild.nodeValue?
eduffy

7
Просто помните, что вы не полагаетесь на детали реализации в xml-генераторе. Там нет никаких гарантий , что первый ребенок текстовый узел , ни только текстовый узел в любых случаях , когда может быть больше , чем один дочерний узел.
Хенрик Густафссон

53
Зачем кому-то разрабатывать библиотеку, в которой значение nodeValue для <name> Smith </name> не равно «Smith» ?! Этот маленький самородок стоил мне 30 минут, чтобы вырвать волосы. Я теперь лысый. Спасибо, минидом.
Assaf Lavie

10
Это просто из-за того, как они разработали его для работы с html, чтобы разрешить такие элементы, как этот <nodeA> Some Text <nodeinthemiddle> __complex__structure__ </nodeinthemiddle> Еще немного текста </nodeA>, в этом случае вы думаете, что nodeA nodeValue должен содержать весь текст, включая сложную структуру, или просто 2 текстовых узла и средний узел. Не лучший способ смотреть на это, но я понимаю, почему они это сделали.
Josh Mc

60

Наверное, что-то вроде этого, если вам нужна текстовая часть ...

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)

Текстовая часть узла считается самим узлом, размещенным как дочерний узел того, который вы просили. Таким образом, вы захотите просмотреть всех его дочерних узлов и найти все дочерние узлы, которые являются текстовыми узлами. Узел может иметь несколько текстовых узлов; например.

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

Вам нужны как blabla, так и znylpx; следовательно, "" .join (). Возможно, вы захотите заменить пробел новой строкой или около того, или, возможно, ничем.


12

вы можете использовать что-то вроде этого. у меня получилось

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

Я знаю, что этот вопрос сейчас довольно старый, но я подумал, что вам будет легче с 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

Я знаю, что это не супер-специфично, но я только что обнаружил это, и пока что намного проще разобраться, чем думать о минидоме (поскольку так много узлов, по сути, являются пустым пространством).

Например, у вас есть имя тега и фактический текст вместе, как и следовало ожидать:

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

8

Приведенный выше ответ правильный, а именно:

name[0].firstChild.nodeValue

Однако для меня, как и для других, моя ценность была ниже по дереву:

name[0].firstChild.firstChild.nodeValue

Чтобы найти это, я использовал следующее:

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 )

Выполнение этого для моего простого файла SVG, созданного с помощью Inkscape, дало мне:

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

Я использовал xml.dom.minidom, различные поля описаны на этой странице, MiniDom Python.


2

У меня был похожий случай, у меня сработало:

name.firstChild.childNodes [0] .data

XML должен быть простым, и это действительно так, и я не знаю, почему мини-дом Python сделал это так сложно ... но именно так это сделано


2

Вот немного измененный ответ Хенрика для нескольких узлов (т.е. когда getElementsByTagName возвращает более одного экземпляра)

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

2

На вопрос дан ответ, мой вклад заключается в разъяснении одной вещи, которая может запутать новичков:

Некоторые из предложенных и правильных ответов использовались, firstChild.dataа другие использовались firstChild.nodeValueвместо них. Если вам интересно, в чем разница между ними, вы должны помнить, что они делают то же самое, потому что nodeValueэто просто псевдоним для data.

Ссылку на мое заявление можно найти как комментарий к исходному коду minidom :

# nodeValue- это псевдоним дляdata


0

Это дерево, и в нем могут быть вложенные элементы. Пытаться:

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.