将列名为属性值的XML读取为pandas DataFrame
问题解决方法
pandas.read_xml本身就支持通过内置参数适配这类结构,不需要依赖xmltodict做手动遍历,下面的方案可以直接复用到所有同结构的XML文件解析场景,比手写遍历逻辑鲁棒性更强。
推荐方案:传入XSLT规则做前置转换(适配规模化使用)
用read_xml自带的stylesheet参数传入一段固定的XSLT转换规则,直接把原XML的嵌套结构转换成pandas默认可识别的扁平行列结构,规则一次编写后所有同结构文件都能直接调用,不需要额外写分支判断。
转换逻辑很明确:
- 把每个
<row>节点映射为DataFrame的一行 - 把
<fld>节点的id属性值作为对应列的列名 - 提取
<fld>下<datVl>节点的文本内容作为单元格的值
实现代码如下:
import pandas as pd # 可全局复用的XSLT转换规则 xslt_template = """ <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="no"/> <xsl:template match="/table"> <root> <xsl:for-each select="row"> <row> <!-- 如需保留row节点自带属性,在这里补充对应取值逻辑即可 --> <xsl:for-each select="fld"> <xsl:element name="{@id}"> <xsl:value-of select="datVl"/> </xsl:element> </xsl:for-each> </row> </xsl:for-each> </root> </xsl:template> </xsl:stylesheet> """ # 直接读取即可得到目标结构,自动兼容单条/多条row的场景 df = pd.read_xml("your_xml_path.xml", stylesheet=xslt_template, xpath=".//row")
运行后得到的结果完全符合预期:
II325A II325B II325C II325D 0 1 2001-12-01 2006-04-30 01 1 2 2006-05-01 2031-11-30 01
这个方案自动解决了你手写逻辑里的边界问题:当XML只包含1个<row>节点时,xmltodict会直接返回字典而非列表,手写遍历需要额外加类型判断,而这个内置方案不需要做任何特殊处理。
备选方案:节点读取后透视(无XSLT依赖)
如果不想使用XSLT,也可以先通过xpath读取所有fld节点,关联所属row的id后再透视成目标结构,适合临时单次使用:
from lxml import etree import pandas as pd # 先解析xml提取所有字段值 tree = etree.parse("your_xml_path.xml") rows = [] for row in tree.xpath("//row"): row_data = {} for fld in row.xpath("./fld"): row_data[fld.get("id")] = fld.xpath("./datVl/text()")[0] rows.append(row_data) df = pd.DataFrame(rows)
这个方案不需要写XSLT,但代码复用性比前者差,遇到结构调整需要改的逻辑更多。
内容的提问来源于stack exchange,提问作者Borut Flis
相关产品推荐
相关产品推荐

