【问题标题】:Find and Replace XML Attributes by Indexing - Python通过索引查找和替换 XML 属性 - Python
【发布时间】:2021-02-11 22:00:21
【问题描述】:

我正在尝试查找 XML 属性并将其替换为基于索引的新值。如果我将属性值本身硬编码到我的查找/替换函数中,我可以替换属性值,但我需要通过索引来执行此操作,特别是对于 和 元素。下面是 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?非常感谢任何帮助!

【问题讨论】:

  • 请显示所需的结果,因为我对您的 attributes 含义感到困惑,因为您没有在代码中显示 elem.attrib 的尝试。
  • 我没有看到希望的结果是如何使用 key 属性的。

标签: python xml attributes lxml elementtree


【解决方案1】:

考虑元素循环,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>

【讨论】:

  • 嘿,@Parfait,感谢您的编辑 - 它工作得非常流畅!对此我深表歉意,但我实际上更新了我原来的问题,以询问如何为两组元素/属性执行此操作。同样的逻辑适用吗?再次感谢!!
  • 嘿,@Parfait,我对我的原始帖子进行了一次(最终)更新,以使 xml 格式更好,并更清楚地提出手头的问题。当我重新运行您的编辑时,我得到以下输出:&lt;Overlay&gt; &lt;foo_1&gt;0.495&lt;bar key="value"&gt;text_1&lt;/bar&gt; &lt;bar key="value"&gt;text_2&lt;/bar&gt; &lt;bar key="value"&gt;text_3&lt;/bar&gt; &lt;/foo_1&gt; &lt;foo_2&gt;0.4&lt;bar key="value"&gt;text_4&lt;/bar&gt; &lt;bar key="value"&gt;text_5&lt;/bar&gt; &lt;bar key="value"&gt;text_6&lt;/bar&gt; &lt;/foo_2&gt; &lt;/Overlay&gt;。 0.495 和 0.4 值需要在 'text_1' 和 'text_4' 所在的位置,但它越来越接近了!
  • 谢谢@Parfait,更新后的嵌套循环效果很好!我会确认这是正确的解决方案,非常感谢! :)
猜你喜欢
  • 2021-05-18
  • 1970-01-01
  • 2021-05-26
  • 1970-01-01
  • 2016-09-06
  • 1970-01-01
  • 2016-03-27
  • 1970-01-01
  • 2011-10-16
相关资源
最近更新 更多