如何用pandas.read_xml解析嵌套XML并生成扁平化DataFrame
问题1:pandas是否有内置功能处理嵌套XML?
没有。pandas.read_xml()默认仅解析指定节点的直接子节点,无法自动递归扁平化嵌套结构,尤其当XML包含命名空间时(如示例中的OECD命名空间),默认行为更受限。虽然可以通过xpath参数指定目标节点,但仍无法自动将所有终端节点展开为DataFrame的列。
问题2:简便的扁平化方法
无需手动定义所有字段,可通过Python内置的XML解析库结合递归函数自动扁平化节点,步骤如下:
1. 处理XML命名空间(关键)
示例XML包含命名空间,解析时需先定义命名空间映射:
import pandas as pd import xml.etree.ElementTree as ET # 解析XML文件 tree = ET.parse('customer_data.xml') root = tree.getroot() # 定义命名空间映射 ns = {'oecd': 'urn:OECD:StandardAuditFile-Taxation/2.00'}
2. 递归扁平化函数
编写递归函数遍历所有终端节点,将嵌套路径转为列名(用下划线分隔父节点与子节点,避免重名冲突):
def flatten_element(element, parent_key='', sep='_'): items = {} for child in element: # 去除命名空间前缀,提取纯节点名 tag = child.tag.split('}')[-1] if '}' in child.tag else child.tag new_key = f"{parent_key}{sep}{tag}" if parent_key else tag # 如果是终端节点(无子节点),直接取值;否则继续递归 if len(child) == 0: items[new_key] = child.text.strip() if child.text else None else: items.update(flatten_element(child, new_key, sep)) return items
3. 提取节点并生成DataFrame
定位所有Customer节点,扁平化后转为DataFrame:
# 查找所有Customer节点 customers = root.findall('.//oecd:Customer', ns) # 扁平化每个Customer节点 flat_data = [flatten_element(cust) for cust in customers] # 转为DataFrame df = pd.DataFrame(flat_data)
结果示例
生成的DataFrame列名包括:RegistrationNumber, Name, Address_StreetName, Address_City, Address_PostalCode, Address_Country, Contact_ContactPerson_FirstName, Contact_ContactPerson_LastName, Contact_Telephone, Contact_Email, TaxRegistration_TaxRegistrationNumber, TaxRegistration_TaxNumber, CustomerID, AccountID, OpeningDebitBalance, ClosingDebitBalance
如果不需要父节点前缀(确保无重名终端节点),可修改函数直接用tag作为键,去掉parent_key拼接逻辑即可。
内容的提问来源于stack exchange,提问作者JCF

