【问题标题】:Parse xml with sub-nodes and create a Pandas dataframe使用子节点解析 xml 并创建 Pandas 数据框
【发布时间】:2021-04-01 15:08:36
【问题描述】:

我的xml格式如下:

<?xml version="1.0" encoding="UTF-8"?>
<results>
   <run>
      <information>
         <logfile>s.log</logfile>
         <version>33</version>
         <mach>1</mach>
         <problemname>mm1</problemname>
         <timestamp>20201218.165122.053486</timestamp>
      </information>
      <controls>
         <item>VARS</item>
      </controls>
      <result>
         <status>4</status>
         <time>3</time>
         <obj>1.0</obj>
         <gap>0.15</gap>
      </result>
   </run>
</results>

在阅读了How to convert an XML file to nice pandas dataframe? 这篇文章后,我在下面有一个示例代码来解析这个文件,但它返回 None。但是,我的问题是,是否有一种快速的方法来创建一个数据框,该数据框包含来自(即 VARS)值和 4 列(即状态、时间、obj 和间隙)的索引。

import pandas as pd
from xml.etree import ElementTree as et

root = (et.parse('test.xml').getroot()).getchildren()


tags = {"tags":[]}
for elem in root:
    tag = {}
    tag["status"] = elem.attrib['status']
    tag["time"] = elem.attrib['time']
    tag["obj"] = elem.attrib['obj']
    tag["gap"] = elem.attrib['gap']
    tags["tags"]. append(tag)

df_users = pd.DataFrame(tags["tags"])
df_users.head()

这是我正在寻找的输出:


      status  time  obj   gap
VARS  4        3    1.0   0.15

【问题讨论】:

  • etree 为您输出什么?我们有点不关心 xml,我们关心 etree 的输出,因为这就是你试图制作 df 的内容。
  • 您的 xml 格式不正确 - 例如,&lt;run&gt;&lt;results&gt; 在哪里关闭?
  • @JackFleeting。谢谢。刚刚更新了。
  • @noah 感谢分享帖子。据此更新了我的问题。

标签: python pandas xml-parsing


【解决方案1】:

我认为您仍然需要遍历 etree 以使用 xml 提取点点滴滴。

import pandas as pd
from xml.etree import ElementTree as et

root = et.parse('test.xml').getroot()

results = []
for ele in eles.findall('run'):
    # assumed each run contains only one control item 
    control = ele.find('controls').find('item').text
    # extract each run result and save it in the results 
    for attr in list(ele.find('result')):
        result = {}
        result['control'] = control
        result[attr.tag] = attr.text
        results.append(result)
# at last, convert into dataframe and set control as index 
results = pd.DataFrame(results)
results = results.set_index('control')

【讨论】:

    【解决方案2】:

    我们可以使用ElementTreefindallfind 方法来提取我们需要的元素(result 的子元素作为列,controls/item 作为索引):

    pd.DataFrame({x.tag: x.text for x in et.findall('./run/result//')},
                 index = [et.find('./run/controls/item').text])
    

    输出:

         status time  obj   gap
    VARS      4    3  1.0  0.15
    

    【讨论】:

      【解决方案3】:

      请注意,状态不在根目录下,但您正试图在根目录下找到它。

      status 在父 result 之下。

      您需要递归检查子项下的状态。

      请参阅documentation。它详细介绍了带有样本的方法。 findall 正如其他人所建议的那样很有用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多