通过 ElementTree 和 Tkinter GUI 在 xml 文件中删除和添加元素时遇到问题。
这只是一段代码的简化部分,这就是为什么我的命名约定可能看起来有点奇怪,而且我对 python 也很陌生(我在 12 年级),不过:
问题是当一个盒子(room0 的子元素)在删除一些其他盒子后添加到 xml 文件时,它会添加以前从 xml 文件中删除的所有盒子,而不是只添加一个盒子。
我的目标是:
按下添加框按钮时,将框添加到 room 0 元素下的 xml 文件
将相应的框移至其减号按钮
然后在减去框后每次按下添加框按钮时可以添加 1 个框(而不是所有被删除的框)
XML 树:(名为“summary.xml”的文件
<data>
<room0 />
</data>
代码:
import tkinter as tk
from tkinter import *
import xml.etree.ElementTree as ET
root = Tk()
#root dimentions
root.geometry("500x560")
root.title("Box & room organiser")
root.resizable(False,False)
root.configure(background = "#2a2828")
#xml
tree = ET.parse("summary.xml")
xmlroot = tree.getroot()
#function that indents and writes xml file when called
def write_xml(tree):
ET.indent(tree, space = '\t', level = 0)
tree.write('summary.xml')
#iterates through the root finding elements of xmlroot
for room0 in xmlroot:
if room0.tag == 'room0':
xml_room0 = room0
#counter variable for amount of boxes in xml file
box_count = 0
def add_box():
global box_count
box_count = box_count + 1
#if box count is 1 add box 1
if box_count == 1:
# adding room0's box 1 to the xml file
for room0 in xmlroot.findall('room0'):
box1=ET.Element('box1')
room0.append(box1)
#alternative way of adding-->
# xml_room0_box1 = ET.SubElement(xml_room0, "box1")
write_xml(tree)
print('box1 added')
elif box_count == 2:
#adding room0's box 2 to the xml file
for room0 in xmlroot.findall('room0'):
box2=ET.Element('box2')
room0.append(box2)
# xml_room0_box2 = ET.SubElement(xml_room0, "box2")
write_xml(tree)
print('box2 added')
elif box_count == 3:
#adding room0's box 3 to the xml file
for room0 in xmlroot.findall('room0'):
box3=ET.Element('box3')
room0.append(box3)
# xml_room0_box3 = ET.SubElement(xml_room0, "box3")
write_xml(tree)
print('box3 added')
elif box_count == 4:
#adding room0's box 4 to the xml file
for room0 in xmlroot.findall('room0'):
box4=ET.Element('box4')
room0.append(box4)
# xml_room0_box4 = ET.SubElement(xml_room0, "box4")
write_xml(tree)
print('box4 added')
elif box_count == 5:
#adding room0's box 5 to the xml file
for room0 in xmlroot.findall('room0'):
box5=ET.Element('box5')
room0.append(box5)
# xml_room0_box5 = ET.SubElement(xml_room0, "box5")
write_xml(tree)
print('box5 added')
elif box_count == 6:
#adding room0's box 6 to the xml file
for room0 in xmlroot.findall('room0'):
box6=ET.Element('box6')
room0.append(box6)
# xml_room0_box6 = ET.SubElement(xml_room0, "box6")
write_xml(tree)
print('box6 added')
add_box_button = Button(root, text = "+", command = add_box)
add_box_button.pack()
#alternative minus code using etree
# from lxml import etree (add at top if using alternative)
# for elem in parse_tree.findall('//box1'): #findall or xpath (no difference)
# parent = elem.getparent()
# parent.remove(elem)
# print(etree.tostring(parse_tree))
# parse_tree.write('summary.xml')
def minus_box1():
#removes box1 element from xml file
global box_count
box_count = box_count - 1
tree =ET.parse('summary.xml')
xml_root = tree.getroot()
for room0 in xml_root:
if room0.tag == 'room0':
for box1 in room0:
if box1.tag == 'box1':
room0.remove(box1)
write_xml(tree)
print('box1 minused')
def minus_box2():
global box_count
box_count = box_count - 1
#removes box1 element from summary.xml
tree=ET.parse('summary.xml')
xmlroot = tree.getroot()
for room0 in xmlroot:
if room0.tag == 'room0':
for box2 in room0:
if box2.tag == 'box2':
room0.remove(box2)
write_xml(tree)
print('box2 minused')
def minus_box3():
global box_count
box_count = box_count - 1
#removes box1 element from summary.xml
tree=ET.parse('summary.xml')
xmlroot = tree.getroot()
for room0 in xmlroot:
if room0.tag == 'room0':
for box3 in room0:
if box3.tag == 'box3':
room0.remove(box3)
write_xml(tree)
print('box3 minused')
def minus_box4():
global box_count
box_count = box_count - 1
#removes box1 element from summary.xml
tree=ET.parse('summary.xml')
xmlroot = tree.getroot()
for room0 in xmlroot:
if room0.tag == 'room0':
for box4 in room0:
if box4.tag == 'box4':
room0.remove(box4)
write_xml(tree)
print('box4 minused')
def minus_box5():
global box_count
box_count = box_count - 1
#removes box1 element from summary.xml
tree=ET.parse('summary.xml')
xmlroot = tree.getroot()
for room0 in xmlroot:
if room0.tag == 'room0':
for box5 in room0:
if box5.tag == 'box5':
room0.remove(box5)
write_xml(tree)
print('box5 minused')
def minus_box6():
global box_count
box_count = box_count - 1
#removes box1 element from summary.xml
tree=ET.parse('summary.xml')
xmlroot = tree.getroot()
for room0 in xmlroot:
if room0.tag == 'room0':
for box6 in room0:
if box6.tag == 'box6':
room0.remove(box6)
write_xml(tree)
print('box6 minused')
#minus box buttons
room0_box1_minus_button = Button(root, text="-b1", bg = "#2b2828", command = minus_box1)
room0_box1_minus_button.pack()
room0_box2_minus_button = Button(root, text="-b2", bg = "#2b2828", command = minus_box2)
room0_box2_minus_button.pack()
room0_box3_minus_button = Button(root, text="-b3", bg = "#2b2828", command = minus_box3)
room0_box3_minus_button.pack()
room0_box4_minus_button = Button(root, text="-b4", bg = "#2b2828", command = minus_box4)
room0_box4_minus_button.pack()
room0_box5_minus_button = Button(root, text="-b5", bg = "#2b2828", command = minus_box5)
room0_box5_minus_button.pack()
room0_box6_minus_button = Button(root, text="-b6", bg = "#2b2828", command = minus_box6)
room0_box6_minus_button.pack()
root.mainloop()
最佳答案
我要做的第一件事是摆脱所有这些 if 语句,无论它们是否导致问题,它们都不是很有效。
我会说将它们替换为一个函数,该函数将以列表的形式从“房间”中获取所有“盒子”。这样你就可以调用 len()
(获取列表的长度)并给出所述房间中所有盒子的数量。
一个简单的函数,像这样
def get_boxes(room):
tree = ET.parse("filename.xml")
root = tree.getroot()
boxList = []
for rooms in root:
if rooms.tag == room:
for boxes in rooms:
boxList.append(boxes.attrib['name'])
return boxList
你也可以摆脱所有这些全局语句,只要你想知道盒子数量,你可以调用 len(get_boxes(roomName))
。
同样,您不需要为每个要删除的不同框都设置一个函数,只要您能知道用户正在选择哪个框,一个简单的删除函数就可以完成,这与以下情况类似:
def remove_box(boxName, boxRoom):
tree = ET.parse("filename.xml")
root = tree.getroot()
for rooms in root:
if rooms.tag == boxRoom:
for boxes in rooms:
if boxes.attrib['name'] == boxName:
rooms.remove(boxes)
break
ET.indent(tree, space = '\t', level=0)
tree.write("filename.xml", "utf-8")
添加框也是一样,你几乎可以完全重用一个函数来添加框。传入盒子名称,它将在哪个房间,函数可以完成剩下的工作。
def create_box(boxName, boxRoom):
tree = ET.parse("filename.xml")
root = tree.getroot()
for rooms in root:
if rooms.tag == boxRoom:
for boxes in rooms:
ET.SubElement(boxes, 'box', name = boxName)
ET.indent(tree, space = '\t', level=0)
tree.write("filename.xml", "utf-8")
一些其他的建议,我会给房间自己的名字,
ET.SubElement("parent", 'room', name = "Kitchen")
你可以用 room.attrib['name'] 找到那个名字,你也可以用盒子做同样的事情。这样一来,您真正需要从用户那里收集的唯一两件事就是他们选择了哪个盒子以及他们所在的房间。
恐怕我无法在 TKinter 方面为您提供帮助,我一直更喜欢 PySimpleGUI,但如果您可以添加和删除框,那么只需将它们添加到添加和删除函数中就可以 够了。
我的代码可能到处都是语法错误,但我希望这对您有所帮助。
关于python,ElementTree,从 xml 文件中添加和删除子元素时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73257173/