【问题标题】:How to update and add attributes in a XML file by using python pandas data frame如何使用 python pandas 数据框更新和添加 XML 文件中的属性
【发布时间】:2020-09-14 19:29:53
【问题描述】:

我是 XML 新手,有没有什么有效的方法可以使用 pandas 数据框匹配文本并更新 XML 文件?

这是我仍然遵循适当格式的大型 XML 文件的一小部分。

XML 文件 (input.xml):

<?xml version="1.0" encoding="UTF-8"?>
<brand by="hhdhdh" date="2014/01/01" name="OOP-112200" Insti="TGA">
   <design name="OOP-112200" own="TGA" descri="" sound_db="JJKO">
      <sec name="abcd" sound_freq="abcd" c_ty="pv">
         <feature number="48">
            <tfgt v="0.1466469683747654" y="0.0" units="sec" />
         </feature>
         <mwan sound_freq="abcd" first_name="g7tty" description="xyz" />
      </sec>
      <sec name="M_20_K40745170" sound_freq="mhr17:7907527-7907589" tension="SGCGSCGSCGSCGSC" s_c="0">
         <feature number="5748">
            <tfgt v="0.1466469683747654" y="0.0" units="sec" />
         </feature>
         <mwan sound_freq="mhr17:7907527-7907589" first_name="g7tty" description="xyz">
        </mwan>
      </sec>
      <sec name="M_20_K40745171" sound_freq="mhr17:7907528-7907599" tension="SGCGSCGSCGSHHGSC" s_c="0">
         <feature number="5748">
            <tfgt v="0.1466469683747654" y="0.0" units="sec" />
         </feature>
         <mwan sound_freq="mhr17:7907527-7907589" first_name="gtftty" description="xyz">
            <xyz abc="trt" id="abc" />
            <per fre="acc" value="abc" />
            <per fre="xyz" value="abc" />
            <per fre="yy" value="abc" />
         </mwan>
      </sec>
      #file continue....
   </design>
</brand>

数据框(用作输入):

                name       Volum_5mb      Volum_40mb     Volum_70mb
1     M_20_K40745170         89.00           44.00         77.00
2     M_20_K40745171         77.00           65.00         94.00

我想匹配来自name 列的元素,如果匹配,则使用列的其余部分来创建新属性,如下所示。例如,如果 df['name'] 中的元素 (M_20_K40745170) 存在/匹配,则在输出文件中分别使用以下行更新相应的节点。

<per fre="Volum_5mb" value="89.00"/>
<per fre="Volum_40mb" value="44.00"/>
<per fre="Volum_70mb" value="77.00"/>

等等。

我希望输出文件看起来像

所需的 XML (output.xml):

<?xml version="1.0" encoding="UTF-8"?>
<brand by="hhdhdh" date="2014/01/01" name="OOP-112200" Insti="TGA">
   <design name="OOP-112200" own="TGA" descri="" sound_db="JJKO">
      <sec name="abcd" sound_freq="abcd" c_ty="pv">
         <feature number="48">
            <tfgt v="0.1466469683747654" y="0.0" units="sec" />
         </feature>
         <mwan sound_freq="abcd" first_name="g7tty" description="xyz" />
      </sec>
      <sec name="M_20_K40745170" sound_freq="mhr17:7907527-7907589" tension="SGCGSCGSCGSCGSC" s_c="0">
         <feature number="5748">
            <tfgt v="0.1466469683747654" y="0.0" units="sec" />
         </feature>
         <mwan sound_freq="mhr17:7907527-7907589" first_name="g7tty" description="xyz">
            <per fre="Volum_5mb" value="89.00" />
            #new attribute FYI
            <per fre="Volum_40mb" value="44.00" />
            #new attribute FYI
            <per fre="Volum_70mb" value="77.00" />
            #new attribute FYI
         </mwan>
      </sec>
      <sec name="M_20_K40745171" sound_freq="mhr17:7907528-7907599" tension="SGCGSCGSCGSHHGSC" s_c="0">
         <feature number="5748">
            <tfgt v="0.1466469683747654" y="0.0" units="sec" />
         </feature>
         <mwan sound_freq="mhr17:7907527-7907589" first_name="gtftty" description="xyz">
            <xyz abc="trt" id="abc" />
            <per fre="acc" value="abc" />
            <per fre="xyz" value="abc" />
            <per fre="yy" value="abc" />
            <per fre="Volum_5mb" value="77.00" />
            #new attribute FYI
            <per fre="Volum_40mb" value="65.00" />
            #new attribute FYI
            <per fre="Volum_70mb" value="94.00" />
            #new attribute FYI
         </mwan>
      </sec>
      #file continue....
   </design>
</brand>

我正在尝试 etree.ElementTree 模块

 import xml.etree.ElementTree as ET
tree = ET.parse('input.xml')
root = tree.getroot()
for i in range(len(df)):
    for node in tree.findall("./design/sec"):
        name = node.attrib.get('name')
        if  name == df.loc[i, 'name']:
            print(name)





        

我是这种 Python-XML 编码的新手。我不知道如何使用 pandas 数据框在 XML 文件中添加新属性。 请帮忙。 谢谢和问候。

【问题讨论】:

  • 首先学习如何使用xlm.etree 以及如何使用Modifying an XML File,因为您的主要问题与pandas 没有直接关系。 node.set("value", "89.00") 怎么样
  • 您可以先找到所有节点,然后将它们与df 一起使用——这样您将只搜索每个节点一次。在当前代码中,您多次搜索同一个节点。
  • 顺便说一句:node = tree.findall('./design/sec[@name="M_20_K40745170"]') 以后你可以做node.find('./per[@fre="Volum_5mb"]\)

标签: python xml pandas elementtree xml.etree


【解决方案1】:

你可以学习xmlxpath,因为主要问题与pandas无关,而是xml

您可以使用更复杂的xpath 来查找名称为M_20_K40745170 和子节点mwam 的节点,您必须在其中搜索pre 并更新它(甚至添加新的pre

node = root.find('./design/sec[@name="M_20_K40745170"]//mwan')

您可以为此使用df.iterrows()

for index, row in df.iterrows():
    node = root.find('./design/sec[@name="{}"]//mwan'.format(row['name']))

以后你可以用"Volum_5mb"搜索per

item = node.find('./per[@fre="Volum_5mb"]')

并创建新的和/或更新值

if not item:  # if item is None:
    item = ET.SubElement(node, 'per')
    item.set('fre', "Volum_5mb")

item.set('value', str(row['Volum_5mb']))

您可以为此使用列表['Volum_5mb', 'Volum_40mb', 'Volum_70mb']

for fre in ['Volum_5mb', 'Volum_40mb', 'Volum_70mb']:

    item = node.find('./per[@fre="{}"]'.format(fre))
    #print(fre, item)

    if not item:
        item = ET.SubElement(node, 'per')
        item.set('fre', fre)

    item.set('value', str(row[fre]))

直接在代码中包含示例数据的最少工作代码,但您应该从文件中读取它们。

text = '''                name       Volum_5mb      Volum_40mb     Volum_70mb
1     M_20_K40745170         89.00           44.00         77.00
2     M_20_K40745171         77.00           65.00         94.00'''

xml = '''<?xml version="1.0" encoding="UTF-8"?>
<brand by="hhdhdh" date="2014/01/01" name="OOP-112200" Insti="TGA">
   <design name="OOP-112200" own="TGA" descri="" sound_db="JJKO">
      <sec name="abcd" sound_freq="abcd" c_ty="pv">
         <feature number="48">
            <tfgt v="0.1466469683747654" y="0.0" units="sec" />
         </feature>
         <mwan sound_freq="abcd" first_name="g7tty" description="xyz" />
      </sec>
      <sec name="M_20_K40745170" sound_freq="mhr17:7907527-7907589" tension="SGCGSCGSCGSCGSC" s_c="0">
         <feature number="5748">
            <tfgt v="0.1466469683747654" y="0.0" units="sec" />
         </feature>
         <mwan sound_freq="mhr17:7907527-7907589" first_name="g7tty" description="xyz">
         </mwan>
      </sec>
      <sec name="M_20_K40745171" sound_freq="mhr17:7907528-7907599" tension="SGCGSCGSCGSHHGSC" s_c="0">
         <feature number="5748">
            <tfgt v="0.1466469683747654" y="0.0" units="sec" />
         </feature>
         <mwan sound_freq="mhr17:7907527-7907589" first_name="gtftty" description="xyz">
            <xyz abc="trt" id="abc" />
            <per fre="acc" value="abc" />
            <per fre="xyz" value="abc" />
            <per fre="yy" value="abc" />
         </mwan>
      </sec>
   </design>
</brand>'''

import pandas as pd
import io
import xml.etree.ElementTree as ET

#df = pd.read_csv('input.csv')
df = pd.read_csv(io.StringIO(text), sep='\s+')
#print(df)

#tree = ET.('input.xml')
#root = tree.getroot()
root = ET.fromstring(xml)
tree = ET.ElementTree(root)

for index, row in df.iterrows():
    node = root.find('./design/sec[@name="{}"]//mwan'.format(row['name']))
    
    for fre in ['Volum_5mb', 'Volum_40mb', 'Volum_70mb']:

        item = node.find('./per[@fre="{}"]'.format(fre))
        #print('item:', fre, '=', item)

        if not item:
            #print('new', item, fre)
            item = ET.SubElement(node, 'per')
            #item.tail = '\n         '  # to pretty print
            item.set('fre', fre)

        item.set('value', str(row[fre]))

    #print(ET.tostring(node).decode())
    
#---
    
print( ET.tostring(root) )
#tree.write('output.xml')

文档:Modifying an XML File

【讨论】:

  • 你正在添加 pre 作为新属性而不是 per 因为你正在搜索/检查 pre with "Volum_5mb" 无论如何你会得到 Nonebtw 感谢您的解释
猜你喜欢
  • 2021-12-31
  • 1970-01-01
  • 2020-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多