通过索引查找和替换 XML 属性 - Python

Find and Replace XML Attributes by Indexing - Python

我正在尝试根据索引查找 XML 属性并将其替换为新值。如果我将属性值本身硬编码到我的 find/replace 函数中,我可以替换属性值,但我需要通过索引这样做,特别是对于 <[= 的前两个列出的具有“文本”值的属性27=]> 和 元素。下面是 XML,以及我正在使用的脚本和要添加到 XML 的新值以及所需的输出:

XML ("foo_bar.xml")

<?xml version="1.0" encoding="UTF-8"?>
<Overlay>
    <foo_1>
        <bar key="value">text_1</bar>
        <bar key="value">text_2</bar>
        <bar key="value">text_3</bar>
    </foo_1>
    <foo_2>
        <bar key="value">text_4</bar>
        <bar key="value">text_5</bar>
        <bar key="value">text_6</bar>
    </foo_2>
</Overlay>

脚本

import lxml.etree as ET
xml = ET.parse("C:\Users\mdl518\Desktop\bar_foo.xml")
tree=xml.getroot()

new_val_1 = float(100/202)
new_val_2 = float(200/500)
new_val_3 = float(4/44)
new_val_4 = float(4/1000)

# Find and replace first and second "bar" subelement attribute values for each "foo" parent element
for elem in tree.getiterator():
    if elem.text:
        elem.text=elem.text.replace(text_1,new_val_1)
    if elem.text:
        elem.text=elem.text.replace(text_2,new_val_2)
    if elem.text:
        elem.text=elem.text.replace(text_4,new_val_3)
    if elem.text:
        elem.text=elem.text.replace(text_5,new_val_4)
    print(elem.text)

想要的结果

<?xml version="1.0" encoding="UTF-8"?>
<Overlay
    <foo_1>
        <bar key="value">new_val_1</bar>
        <bar key="value">new_val_2</bar>
        <bar key="value">text</bar>
    </foo_1>
    <foo_2>
        <bar key="value">new_val_3</bar>
        <bar key="value">new_val_4</bar>
        <bar key="value">text</bar>
    </foo_2>
</Overlay>

有没有一种方便的方法来索引子元素属性值并将它们替换为所需的值(即“new_val_#”)并写入XML?非常感谢任何帮助!

考虑按元素循环 zip,在您需要的值和 iterfind 生成器的列表中。 运行 用于对齐元素和值集的嵌套循环。也没有必要检查 if elem.text 因为每个 XML 元素都有一个底层文本节点(空与否)。如果整个字符串包含 text,只需分配而不是 replace。请注意:zip 停止在较短的列表上按元素循环:

# LIST OF VALUES
new_vals = [float(100/202), float(200/500), float(4/44), float(4/1000)]

# SUBLIST OF VALUES BY 2 (ADJUST 2 FOR ANY OTHER NUMBER)
sub_new_vals = [new_vals[i:i+2]  for i in range(0, len(new_vals), 2)]

for nvs, el in zip(sub_new_vals, tree.iterfind('./*')):
    # Find and replace first and second attribute values
    for nv, elem in zip(nvs, el.iterfind('./*')):
        #elem.attrib["key"] = str(round(nv, 3))       # UPDATE ATTRIBUTE VALUE
        elem.text = str(round(nv, 3))                 # UPDATE ELEMENT TEXT
        print(elem.text)
                          
output = ET.tostring(tree, 
                     encoding="UTF-8",
                     method="xml", 
                     xml_declaration=True, 
                     pretty_print=True)
  
print(output.decode("utf-8"))

输出

0.495
0.4
0.091
0.004
<?xml version='1.0' encoding='UTF-8'?>
<Overlay>
    <foo_1>
        <bar key="value">0.495</bar>
        <bar key="value">0.4</bar>
        <bar key="value">text_3</bar>
    </foo_1>
    <foo_2>
        <bar key="value">0.091</bar>
        <bar key="value">0.004</bar>
        <bar key="value">text_6</bar>
    </foo_2>
</Overlay>