求助:将API返回的XML数据转换为Pandas DataFrame
把XML转换为Pandas DataFrame的完整解决方案
问题背景
给定以下XML格式的API响应:
<?xml version="1.0" encoding="UTF-8"?> <sunSpecPlantExtract t="2022-08-09T16:54:53Z"><plant id="bb2c469c-9b63-4e64-b95c-6806578889ae" v="1" locale="en-US"><name>Palmyra LLC / Unique Smile</name><activationDate>2016-07-11</activationDate><location><latitude/><longitude/><line1>21 Main St.</line1><city>Milford</city><state>MA</state><postal>01757</postal><timezone>-4:00</timezone></location></plant><sunspecData v="1" periodStart="2022-08-08T06:00:00Z" periodEnd="2022-08-08T23:59:00Z"><d lid="00:90:C2:F7:8C:9C" man="solren" mod="2_20151205" t="2022-08-08T23:40:56Z"><m id="201" sn="F78C9C"><p id="WH">127100</p><p id="WHL">157155200</p><p id="W">9357.4</p></m></d></sunspecData></sunSpecPlantExtract>
使用以下代码转换时,无法提取完整数据:
root = ET.XML(response_data) # element tree all_records = [] for i, child in enumerate(root): record = {} for subchild in child: record[subchild.tag] = subchild.text all_records.append(record) return pd.DataFrame(all_records)
得到的不完整结果:
name activationDate location d 0 Jack Efird #35 2019-07-03 NaN NaN 1 NaN NaN NaN NaN
问题分析
原代码存在以下局限:
- 仅遍历根节点的直接子元素(
plant和sunspecData),将关联数据拆分为两条独立记录,不符合业务逻辑 - 未提取元素的属性信息(如
plant的id、sunspecData的periodStart等) - 未处理嵌套结构(如
location下的子字段、d/m/p层级的数据) - 忽略了空元素和非叶子节点的内容提取
完整解决方案
使用递归方式提取XML中的所有属性和嵌套子元素,将关联数据合并为单条记录后转换为DataFrame:
import xml.etree.ElementTree as ET import pandas as pd def extract_element_data(element, parent_key=''): data = {} # 提取当前元素的所有属性 for attr, value in element.attrib.items(): key = f"{parent_key}_{attr}" if parent_key else attr data[key] = value # 递归处理子元素 for child in element: child_key = f"{parent_key}_{child.tag}" if parent_key else child.tag # 处理叶子节点(无嵌套子元素且有有效文本) if len(child) == 0: if child.text and child.text.strip(): data[child_key] = child.text.strip() else: # 处理嵌套节点,递归提取后合并数据 child_data = extract_element_data(child, child_key) data.update(child_data) return data # 解析XML数据(替换为你的response_data变量) response_data = """<?xml version="1.0" encoding="UTF-8"?> <sunSpecPlantExtract t="2022-08-09T16:54:53Z"><plant id="bb2c469c-9b63-4e64-b95c-6806578889ae" v="1" locale="en-US"><name>Palmyra LLC / Unique Smile</name><activationDate>2016-07-11</activationDate><location><latitude/><longitude/><line1>21 Main St.</line1><city>Milford</city><state>MA</state><postal>01757</postal><timezone>-4:00</timezone></location></plant><sunspecData v="1" periodStart="2022-08-08T06:00:00Z" periodEnd="2022-08-08T23:59:00Z"><d lid="00:90:C2:F7:8C:9C" man="solren" mod="2_20151205" t="2022-08-08T23:40:56Z"><m id="201" sn="F78C9C"><p id="WH">127100</p><p id="WHL">157155200</p><p id="W">9357.4</p></m></d></sunspecData></sunSpecPlantExtract> """ root = ET.fromstring(response_data) # 合并所有节点的数据为单条记录 full_record = {} for child_node in root: node_data = extract_element_data(child_node) full_record.update(node_data) # 转换为DataFrame df = pd.DataFrame([full_record]) print(df)
输出结果
运行后将得到包含所有字段的完整DataFrame:
sunSpecPlantExtract_t plant_id plant_v plant_locale name activationDate location_latitude location_longitude location_line1 location_city location_state location_postal location_timezone sunspecData_v sunspecData_periodStart sunspecData_periodEnd d_lid d_man d_mod d_t m_id m_sn p_WH p_WHL p_W 0 2022-08-09T16:54:53Z bb2c469c-9b63-4e64-b95c-... 1 en-US Palmyra LLC / Unique Smile 2016-07-11 21 Main St. Milford MA 01757 -4:00 1 2022-08-08T06:00:00Z 2022-08-08T23:59:00Z 00:90:C2:F7:8C:9C solren 2_20151205 2022-08-08T23:40:56Z 201 F78C9C 127100 157155200 9357.4
内容的提问来源于stack exchange,提问作者GKV
相关产品推荐
相关产品推荐

