使用lxml访问父元素的子元素有更优雅的方式吗

1 投票
1 回答
1115 浏览
提问于 2025-04-16 00:21

我正在研究XBRL文档,想弄清楚如何有效地提取和使用其中的数据。其中一个让我困惑的地方是如何正确使用上下文信息。下面是我正在处理的文档中的一段内容(这是来自美泰公司的最新10-K报告)

我希望能够高效地收集上下文的键值对,因为它们对对齐“真实数据”非常重要。这里有一个上下文元素的例子:

- <context id="eol_PE6050----0910-K0010_STD_0_20091231_0">
  - <entity>
     <identifier scheme="http://www.sec.gov/CIK">0000063276</identifier> 
   </entity>
  - <period>
   <instant>2009-12-31</instant> 
   </period>
   </context>

刚开始的时候,我以为如果有父子关系,我应该能直接从父元素获取所有子元素的属性、键、值和文本,只需要对父元素应用一个方法就行。但是,子元素虽然可以从父元素找到,但它们依然是独立的。我的意思是,如果子元素有属性、键、值或文本,这些信息不能直接从父元素访问,而是需要先确定/识别子元素,然后再从子元素中获取所需的数据或元数据。

我不太确定为什么这段代码是一个好的起点:

 from lxml import etree
 test_tree=etree.parse(r'c:\temp\test_xml\mat-20091231.xml')
 tree_list=[p for p in test_tree.getiterator() 

所以我的tree_list是我在xml文件中确定存在的元素的列表
因为我的tree_list中只有664个项目,我错误地假设所有的元素都包含在父元素中,所以我一直试图通过引用这些元素(而不是它们的子元素)来访问实体、期间和瞬时。

for each in tree_list:
    if 'context' in each.tag:
        contextlist.append(each)

也就是说,我一直对上下文列表中的项目应用不同的方法,结果非常沮丧。最后,当我在写这个问题的时候,我试图找一些帮助来弄清楚哪个方法能给我实体和期间,我决定尝试一下。

children=[c for c in contextlist[0].iterchildren()]

所以我的children列表包含了上下文列表中第一个项目的所有子元素。

其中一个子元素是实体元素,另一个是期间元素。

现在,每个子元素应该都有一个子元素,实体元素有一个标识符子元素,而期间元素有一个瞬时子元素。这比我今天早上想的要复杂得多。

我必须了解上下文元素报告的细节,才能正确评估和操作真实数据。看起来我需要测试上下文元素的每一个子元素。有没有更快、更有效的方法来获取这些值?换句话说,有没有办法从某个元素创建一个数据结构,包含它的所有子元素和孙子元素等,而不需要进行大量的尝试和条件判断?

一旦我有了这些信息,我就可以开始构建数据字典,并根据上下文将数据元素分配给特定的条目。因此,高效且完整地获取上下文元素对我的任务至关重要。

1 个回答

3

使用元素树接口(lxml也支持这个),getiterator 可以遍历当前元素下面的所有节点。

所以,[list(c.getiterator()) for c in contextlist] 会给你想要的列表的列表(或者你也可以选择把c保留在结果列表中,这样就不用再和contextlist配对了,也就是说可以直接生成一个元组列表[(c, list(c.getiterator())) for c in contextlist],具体看你怎么用)。

顺便提一下,像[x for x in whatever]这样的列表推导式其实没什么意义——用list(whatever)来把其他可迭代的东西转换成列表会更好。

撰写回答