รับค่าองค์ประกอบด้วย minidom ด้วย Python


109

ฉันกำลังสร้างส่วนหน้า GUI สำหรับ Eve Online API ใน Python

ฉันดึงข้อมูล XML จากเซิร์ฟเวอร์สำเร็จแล้ว

ฉันพยายามดึงค่าจากโหนดชื่อ "name":

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

ดูเหมือนว่าจะพบโหนด แต่ผลลัพธ์อยู่ด้านล่าง:

[<DOM Element: name at 0x11e6d28>]

ฉันจะพิมพ์ค่าของโหนดได้อย่างไร


5
ดูเหมือนว่าคำตอบสำหรับคำถาม "minidom" ส่วนใหญ่คือ "use ElementTree"
Warren P

คำตอบ:


156

มันควรจะเป็น

name[0].firstChild.nodeValue

4
เมื่อฉันตั้งชื่อ [0] .nodeValue กลับเป็น "None" เพียงเพื่อทดสอบว่าฉันส่งชื่อ [0] .nodeName และให้ "ชื่อ" ซึ่งถูกต้อง ความคิดใด ๆ ?
RailsSon

28
ชื่อ [0] .firstChild.nodeValue ล่ะ?
eduffy

7
เพียงระวังว่าคุณไม่ได้อาศัยรายละเอียดการใช้งานใน xml-generator มีไม่รับประกันว่าลูกคนแรกเป็นโหนดข้อความหรือเพียงโหนดข้อความในกรณีใด ๆ ที่สามารถมีได้มากกว่าหนึ่งโหนดเด็ก
Henrik Gustafsson

53
ทำไมใคร ๆ ก็ออกแบบห้องสมุดที่ nodeValue ของ <name> Smith </name> เป็นอะไรก็ได้นอกจาก "Smith"! นักเก็ตตัวเล็ก ๆ คนนั้นใช้เวลาฉีกผม 30 นาที ตอนนี้ฉันหัวโล้น ขอบคุณ minidom
Assaf Lavie

10
เป็นเพียงเพราะวิธีที่พวกเขาออกแบบให้ทำงานกับ html เพื่ออนุญาตให้ใช้องค์ประกอบเช่น <nodeA> ข้อความบางส่วน <nodeinthemiddle> __complex__structure__ </nodeinthemiddle> ข้อความเพิ่มเติม </nodeA> ในกรณีนี้คุณคิดว่า nodeValue ของ nodeA ควรมีข้อความทั้งหมดรวมถึงโครงสร้างที่ซับซ้อนหรือเพียง 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

นี่คือคำตอบที่ปรับเปลี่ยนเล็กน้อยของ Henrik สำหรับหลายโหนด (เช่นเมื่อ 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แทน ในกรณีที่คุณกำลังสงสัยว่าสิ่งที่แตกต่างระหว่างพวกเขาคุณควรจำไว้พวกเขาทำสิ่งเดียวกันเพราะเป็นเพียงนามแฝงสำหรับnodeValuedata

การอ้างอิงถึงคำสั่งของฉันสามารถพบได้ในความคิดเห็นเกี่ยวกับซอร์สโค้ดของ 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.