I'm getting an issue when removing and adding elements to a xml file via ElementTree and Tkinter GUI.

This is just a simplified part of a piece of code that's why my naming conventions may seem a little weird and I'm also fairly new to python (I'm in year 12), nevertheless:

The issue is when a box(subelement of room0) is added to the xml file after removing some other boxes it adds all the boxes that were previously removed from the xml file, instead of just one.

my goal is to:

  • add boxes to the xml file under the room 0 element when the add box button is pressed

  • remove the respective box to its minus button

  • then be able to add 1 box per time the add box button is pressed (instead all that were removed) after subtracting boxes

XML tree: (file called "summary.xml"

<data>
    <room0 />
</data>

Code:

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

推荐答案

The first thing I'd do is get rid of all of those if statements, weather they're causing the problem or not, they aren't very efficient.

I'd say replace them with a function that will get all of the 'boxes' from a 'room' in form of a list. That way you can just call len() (which gets the length of a list) and give you the number of all boxes in said room.

A simple function, something like this

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

You can also get rid of all of those global statements, whenever you want to know the box count you can just call len(get_boxes(roomName)).

Similarly, you don't need a function for every different box you remove, aslong as you can get which box the user is selecting a simple remove function will do, not unlike:

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")

It's the same story for adding a box, you can almost completely reuse a function to add boxes. Pass in the boxes name, which room it will be in, and the function can do the rest

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")

Some other suggestions, I would give the rooms there own names,

ET.SubElement("parent", 'room', name = "Kitchen")

and you can find that name with room.attrib['name'], you could do the same with boxes as well. That way the only two things you really need to collect from the user is what box they have selected and what room they are in.

I'm afraid I can't help you with the TKinter side of things, I always preferred PySimpleGUI, but if you can add and remove boxes, then just adding them into the add and remove functions could be enough.

My code is probably splattered with syntax errors, but I hope this helps.

Python相关问答推荐

当我用键绑定更改 self.surf 时,如何阻止我的角色缩小?

如何在python中循环菜单 Select 验证?

如何让键绑定在 pygame 中工作?

如何处理在 FastAPI 中混淆的路径操作?

制作派生自由python中的类型通知的数据类对象的类工厂

从坐标数组中查找特定坐标的位置

如何在知道起始坐标、线长 x Angular 和 y、Angular 的情况下画线

AttributeError:“元组”对象没有“排序”属性

将 n 个文件中的两个 csv 文件合并,并使用 pandas 在文件夹中生成新的 csv 文件

在 PyTorch 中读取 .pyth 文件类型

Keras Dropout 是如何实际执行的?

使用 biopython 从外部 pubmed ID 列表中从 pubmed 中提取多个摘要

在列中查找部分文本,如果找到 true,则传递 a 通过反映分配的文本值而不是 true 或 false 来创建新列

有没有办法计算数据框中至少包含一个“1”的所有行,判断多个命名列?

Pandas:包含对列表的列

具有多个参数的用户定义函数返回 NULL 值

更改字典中的键

Leetcode 752:用 BFS 开锁 TLE

从数据框中 Select 特定列

如何根据Python中的分隔符在python中将一行拆分为两行