Dapatkan nilai Elemen dengan minidom dengan Python

109

Saya membuat antarmuka GUI untuk Eve Online API dengan Python.

Saya telah berhasil menarik data XML dari server mereka.

Saya mencoba mengambil nilai dari node yang disebut "nama":

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

Ini tampaknya menemukan node, tetapi outputnya di bawah:

[<DOM Element: name at 0x11e6d28>]

Bagaimana saya bisa mendapatkannya untuk mencetak nilai node?

RailsSon
sumber
5
Sepertinya jawaban untuk sebagian besar pertanyaan "minidom" adalah "gunakan ElementTree".
Warren P

Jawaban:

156

Seharusnya begitu

name[0].firstChild.nodeValue
eduffy
sumber
4
Ketika saya melakukan name [0] .nodeValue memberikan kembali "None", hanya untuk menguji saya memberikannya nama [0] .nodeName dan memberi saya "nama" yang benar. Ada ide?
RailsS
28
Bagaimana dengan name [0] .firstChild.nodeValue?
eduffy
7
Berhati-hatilah karena Anda tidak mengandalkan detail implementasi di xml-generator. Tidak ada jaminan bahwa anak pertama adalah yang simpul teks maupun hanya simpul teks dalam kasus di mana bisa ada lebih dari satu node anak.
Henrik Gustafsson
53
Mengapa ada orang yang mendesain perpustakaan di mana nodeValue dari <name> Smith </name> tidak lain adalah "Smith" ?! Bongkahan kecil itu menghabiskan waktu 30 menit untuk merobek rambutku. Saya botak sekarang. Terima kasih, minidom.
Assaf Lavie
10
Itu hanya karena cara mereka mendesainnya untuk bekerja dengan html, untuk memungkinkan elemen seperti ini <nodeA> Beberapa Teks <nodeinthemiddle> __complex__structure__ </nodeinthemiddle> Beberapa teks lagi </nodeA>, dalam hal ini menurut Anda nodeValue nodeA harus berisi semua teks termasuk struktur kompleks, atau hanya 2 node teks dan node tengah. Bukan cara terbaik untuk melihatnya, tapi saya bisa mengerti mengapa mereka melakukannya.
Josh Mc
60

Mungkin sesuatu seperti ini jika itu bagian teks yang Anda inginkan ...

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)

Bagian teks dari sebuah simpul dianggap sebagai simpul itu sendiri ditempatkan sebagai simpul anak dari yang Anda minta. Jadi, Anda akan ingin menelusuri semua anaknya dan menemukan semua simpul anak yang merupakan simpul teks. Sebuah node dapat memiliki beberapa node teks; misalnya.

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

Anda menginginkan 'blabla' dan 'znylpx'; maka "" .join (). Anda mungkin ingin mengganti spasi dengan baris baru atau lebih, atau mungkin tidak sama sekali.

Henrik Gustafsson
sumber
12

Anda dapat menggunakan sesuatu seperti ini. Itu berhasil untuk saya

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
sumber
8

Saya tahu pertanyaan ini sudah cukup lama sekarang, tetapi saya pikir Anda mungkin akan lebih mudah menggunakan 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

Saya tahu itu tidak super spesifik, tetapi saya baru saja menemukannya, dan sejauh ini jauh lebih mudah untuk memahami daripada minidom (karena begitu banyak node pada dasarnya adalah ruang putih).

Misalnya, Anda memiliki nama tag dan teks yang sebenarnya, seperti yang mungkin Anda harapkan:

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

Jawaban diatas benar yaitu:

name[0].firstChild.nodeValue

Namun bagi saya, seperti orang lain, nilai saya jauh di bawah pohon:

name[0].firstChild.firstChild.nodeValue

Untuk menemukan ini saya menggunakan yang berikut:

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 )

Menjalankan ini untuk file SVG sederhana saya yang dibuat dengan Inkscape, ini memberi saya:

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

Saya menggunakan xml.dom.minidom, berbagai bidang dijelaskan di halaman ini, MiniDom Python.

LazyBrush
sumber
2

Saya memiliki kasus serupa, yang berhasil untuk saya adalah:

name.firstChild.childNodes [0] .data

XML seharusnya sederhana dan memang begitu dan saya tidak tahu mengapa minidom python melakukannya begitu rumit ... tapi begitulah cara membuatnya

robertzp
sumber
2

Berikut adalah jawaban Henrik yang sedikit dimodifikasi untuk beberapa node (mis. Ketika getElementsByTagName mengembalikan lebih dari satu 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
sumber
2

Pertanyaan sudah terjawab, kontribusi saya adalah mengklarifikasi satu hal yang mungkin membingungkan pemula:

Beberapa dari jawaban yang disarankan dan benar digunakan firstChild.datadan yang lainnya digunakan firstChild.nodeValuesebagai gantinya. Jika Anda bertanya-tanya apa perbedaan di antara mereka, Anda harus ingat mereka melakukan hal yang sama karena nodeValuehanya alias untukdata .

Referensi ke pernyataan saya dapat ditemukan sebagai komentar di kode sumber minidom :

# nodeValueadalah alias untukdata

Billal Begueradj
sumber
0

Itu pohon, dan mungkin ada elemen bersarang. Mencoba:

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
sumber