You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用yield递归遍历XML并生成可构建DataFrame的路径与值?

处理深层嵌套XML:生成元素路径与值的DataFrame

我正在处理一个嵌套层级极深的XML文件,元素路径对理解数据至关重要。参考相关Python代码,我能打印出元素的路径和对应值,但没法把结果输出成更易用的格式——目标是构建包含Path和Value列的DataFrame。

示例XML结构

<A>
  <B>foo</B>
  <C>
    <D>On</D>
  </C>
  <E>Auto</E>
  <F>
    <G>
      <H>shoo</H>
      <I>Off</I>
    </G>
  </F>
</A>

可正常打印路径和值的代码

from lxml import etree
root = etree.XML(your_xml_string)

def print_path_of_elems(elem, elem_path=""):
    for child in elem:
        if not child.getchildren() and child.text:
            # 叶子节点且有文本 => 打印
            print "%s/%s, %s" % (elem_path, child.tag, child.text)
        else:
            # 有子元素的节点 => 递归处理
            print_path_of_elems(child, "%s/%s" % (elem_path, child.tag))

print_path_of_elems(root, root.tag)

输出结果

/A/B, foo
/A/C/D, On
/A/E, Auto
/A/F/G/H, shoo
/A/F/G/I, Off

尝试用yield生成数据但失败的代码

from lxml import etree
root = etree.XML(your_xml_string)

def yield_path_of_elems(elem, elem_path=""):
    for child in elem:
        if not child.getchildren() and child.text:
            ylddict = {'Path':elem_path, 'Value':child.text}
            yield(ylddict)
        else:
            # 有子元素的节点 => 递归处理
            yield_path_of_elems(child, "%s/%s" % (elem_path, child.tag))

for i in yield_path_of_elems(root):
    # 示例中打印,实际要转为DataFrame
    print(i)

测试发现用yield或return时递归无法正常工作。


解决方案

问题核心是递归调用生成器时,没有传递子生成器的结果。你需要用yield from(Python 3.3+)或者手动迭代子生成器来yield其返回值。

修正后的代码

from lxml import etree
import pandas as pd

root = etree.XML(your_xml_string)

def yield_path_of_elems(elem, elem_path=""):
    # 拼接当前节点的路径,避免开头出现多余斜杠
    current_path = f"{elem_path}/{elem.tag}" if elem_path else elem.tag
    for child in elem:
        # 判断是否为有效叶子节点:无后代元素,且有非空文本
        if not child.getchildren() and child.text and child.text.strip():
            full_path = f"{current_path}/{child.tag}"
            yield {'Path': full_path, 'Value': child.text.strip()}
        else:
            # 递归处理子节点,用yield from传递生成器结果
            yield from yield_path_of_elems(child, current_path)

# 生成数据并转为DataFrame
data_list = list(yield_path_of_elems(root))
df = pd.DataFrame(data_list)
print(df)

关键修改说明

  1. yield from处理递归:确保子生成器的每个结果都能被外层生成器输出,解决递归时无返回值的问题
  2. 路径优化:修正路径拼接逻辑,避免出现类似//A/B的错误格式
  3. 空文本过滤:用child.text.strip()过滤掉无实际内容的节点
  4. 直接生成DataFrame:将生成器转为列表后,直接传入pandas创建DataFrame

输出结果

Path  Value
0        /A/B    foo
1      /A/C/D     On
2        /A/E   Auto
3    /A/F/G/H   shoo
4    /A/F/G/I    Off

Python 2.x兼容版本

如果使用Python 2.x(不支持yield from),可手动循环子生成器:

else:
    for item in yield_path_of_elems(child, current_path):
        yield item

内容的提问来源于stack exchange,提问作者richtopia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 16:20:32