Python在循环字典和替换xml属性时遇到麻烦

时间:2016-09-22 20:56:50

标签: python xml loops dictionary

我无法在下面的Python列表中循环,并将xml属性替换为所有 ADSType 值。

Python词典

{'ADSType': ['HS11N', 'HS11V'], 'Type': ['Bond', 'Cash']}

XML

我想用XML替换XML中每一行的 sid 值。

<req Times="1" action="get" chunklimit="1000" lang="ENU" msg="1" rank="1" rnklst="1" runuf="0">
<flds>
        <f end="2016-02-29" freq="m" i="bond(long) hff" sid="abc" start="2016-02-29" />
        <f end="2016-02-29" freq="m" i="bond(short) ggg" sid="abc" start="2016-02-29" />
</flds>
<dat>
        <r CalculationType="3" ForceCalculate="1" i="123" />
</dat>
</req>
到目前为止

Python代码:

data_list = {'ADSType': ['HS11N', 'HS11V'], 'Type': ['Bond', 'Cash']}

xml_file = './test.xml'
tree1 = ET.ElementTree(file=xml_file)
root1 = tree1.getroot()

for x in root1.iter('flds'):
    for y in x.iter('f'):
        y.set('sid', y.get('sid').replace("123", "abc"))
# print(ET.tostring(root1).decode("UTF-8"))
    print "test"
# print(ET.tostring(root1).decode("UTF-8"))
tree1.write("./test.xml")

我陷入困境,如何迭代列表,提取值,动态地输入替换方法并更新xml。请帮忙!以下是我想要实现的理想输出。

<req Times="1" action="get" chunklimit="1000" lang="ENU" msg="1" rank="1" rnklst="1" runuf="0">
<flds>
        <f end="2016-02-29" freq="m" i="bond(long) hff" sid="HS11N" start="2016-02-29" />
        <f end="2016-02-29" freq="m" i="bond(short) ggg" sid="HS11V" start="2016-02-29" />
</flds>
<dat>
        <r CalculationType="3" ForceCalculate="1" i="123" />
</dat>
</req>

2 个答案:

答案 0 :(得分:2)

您无需替换任何内容,只需将 set 与将覆盖的新值一起使用:

from xml.etree import ElementTree as ET
xml_file = "./test.xml"

tree = ET.parse(xml_file)
root1 = tree.getroot()
data_list = {'ADSType':['HS11N', 'HS11V'], 'Type': ['Bond', 'Cash']}

# make iterator so we just call next(sids) to pull each value
sids = iter(data_list['ADSType'])

for flds in root1.iter('flds'):
    for f in flds.iter('f'):
        # set to new value
        f.set("sid", next(sids))
# write
tree.write("./test.xml")

这完全符合你的要求,虽然我不确定完整的dict如何适合你的问题:

的test.xml:

In [3]: !cat test.xml
<req Times="1" action="get" chunklimit="1000" lang="ENU" msg="1" rank="1" rnklst="1" runuf="0">
    <flds>
        <f end="2016-02-29" freq="m" i="bond(long) hff" sid="abc" start="2016-02-29" />
        <f end="2016-02-29" freq="m" i="bond(short) ggg" sid="abc" start="2016-02-29" />
    </flds>
    <dat>
        <r CalculationType="3" ForceCalculate="1" i="123" />
    </dat>
</req>

运行代码:

In [4]: from xml.etree import ElementTree as ET

In [5]: xml_file = "./test.xml"

In [6]: tree = ET.parse(xml_file)

In [7]: root1 = tree.getroot()

In [8]: data_list = {'ADSType': iter(['HS11N', 'HS11V']), 'Type': iter(['Bond', 'Cash'])}

In [9]: sids = iter(data_list['ADSType'])

In [10]: for flds in root1.iter('flds'):
   ....:     for f in x.iter('f'):
   ....:              f.set("sid", next(sids))
   ....: tree.write("./test.xml")
   ....: 

新的test.xml:

In [11]: !cat test.xml
<req Times="1" action="get" chunklimit="1000" lang="ENU" msg="1" rank="1" rnklst="1" runuf="0">
    <flds>
        <f end="2016-02-29" freq="m" i="bond(long) hff" sid="HS11N" start="2016-02-29" />
        <f end="2016-02-29" freq="m" i="bond(short) ggg" sid="HS11V" start="2016-02-29" />
    </flds>
    <dat>
        <r CalculationType="3" ForceCalculate="1" i="123" />
    </dat>
</req>

如果你在多个fld中有多个f并希望循环这些值,请使用 itertools.cycle 代替iter:

from itertools import cycle
sids = cycle(data_list['ADSType'])

答案 1 :(得分:-2)

这是一种快速而肮脏的方式。

for x in root1.iter('flds'):
    f = x.iter('f')
    for idx,y in enumerate(x):
        if y < len(f):
            y.set('sid', y.get('sid').replace("abc",data_list['ADSType'][y]))

只需使用enumerate在XML中获取f的索引。然后将其用于data_list ADSType中的索引。

未添加任何XML验证以确保要替换的属性存在。我也没有考虑多个'flds'标签。在平板电脑上写这么难以添加更强大的代码。回到笔记本电脑时,我会尝试用更快速和更脏的东西进行更新