将NBB XBRL转换为DataFrame

问题描述 投票:0回答:1

总结

比利时国家银行 (NBB) 通过其 API 向公众提供上市公司的财务报表。自 2022 年起,这些可以以 JSON 文件形式请求。之前仅在 XBRL 中。

这个问题是关于 XBRL 的。

来源

据我了解(可能是简化的),XBRL 是常规 XML 文件,此外还能够引用分类法,即为元素内的属性提供“字典”,以便为元素中封装的内容提供语义含义.

示例

<xbrldi:typedMember dimension="dim:afnp"><open:str>John</open:str></xbrldi:typedMember>

鉴于命名空间可用,在某一点或另一点,

dim:afnp
应指向标签
first_name
或相等。

我希望能够将此 XBRL 数据转换为 Pandas DataFrame(或 .csv)

重现障碍物

由于 API 密钥是必要的,我将提供一段我认为应该足够的匿名代码。该分类法可在我提供的第二个链接中下载 (.zip)。它只是一个包含有组织的文件夹的目录,与命名空间类似,最终会导致其他 xml/xld 文件。

来自 API 的数据如下所示:

<xbrl 
xml:lang="nl"
 xmlns="http://www.xbrl.org/2003/instance"
 xmlns:link="http://www.xbrl.org/2003/linkbase"
 xmlns:xbrldi="http://xbrl.org/2006/xbrldi"
 xmlns:xlink="http://www.w3.org/1999/xlink"
 xmlns:iso4217="http://www.xbrl.org/2003/iso4217"
 xmlns:dim="http://www.nbb.be/be/fr/cbso/dict/dim"
>
<!--More namespaces are given but I believe irrelevant here-->

<link:schemaRef xlink:type="simple" xlink:href="http://www.nbb.be/be/fr/cbso/fws/23.0/mod/m87/m87-f.xsd"/>

<!--The file repeats itself with <context> elements, just different id's.-->

<context id="c19">
<entity><identifier scheme="http://www.fgov.be">Some number</identifier></entity>
<period><instant>Some date</instant></period>
<scenario>
<xbrldi:typedMember dimension="dim:afnp"><open:str>John</open:str></xbrldi:typedMember>
<xbrldi:typedMember dimension="dim:annp"><open:str>Doe</open:str></xbrldi:typedMember>
<xbrldi:explicitMember dimension="dim:bas">bas:m31</xbrldi:explicitMember>
<xbrldi:explicitMember dimension="dim:ctc">ctc:m1</xbrldi:explicitMember>
<xbrldi:explicitMember dimension="dim:part">part:m2</xbrldi:explicitMember>
<xbrldi:explicitMember dimension="dim:psn">psn:m12</xbrldi:explicitMember>
</scenario>
</context>
</xbrl>"""

stringIO_xml = StringIO(xml)

我尝试过什么?

我从 Arelle 开始,但在我看来,他们的文档不是很有帮助,至少对于外行来说不是。我没有真正得到结果,我觉得问题在于将分类法提供为本地文件夹(而不是 HTTP 链接)。此外,他们的 GUI 不接受 .zip 文件(它崩溃了)。我还没有尝试过 CLI。

我还读到了有关 Brel 的文章,我认为它更关注来自美国的 EDGAR。

但是,我觉得探索 Pandas

pd.read_xml()
lxml
并致力于定制脚本来解码财务信息更有趣。

我注意到

pd.read_xml()
提供了参数
namespaces
,它接受
dict
。由于分类法是静态的,因此只需完成一次到字典的转换。

我想也许提供本地文件夹的链接可能会有所帮助。

我已经尝试过:

pd.read_xml(stringIO_xml, namespaces={'dim':'file:////Users/myname/Downloads/nbb-cbso-23.0.1/www.nbb.be/be/fr/cbso/dict/dim'})

三个

///
用于文件,一个
/
作为我的绝对路径的开头。

但是出现错误:

XMLSyntaxError: Namespace prefix open on str is not defined, line 16, column 51

如果我读到的错误是正确的,那就是

<open:str>John</open:str>
,我什至不知道如何反驳。

我的问题

我会尽力具体说明。根据我提供的信息:
  • 当我说即使从本地文件夹提供分类法时,我的逻辑是否有缺陷,只需正确构建我的论点以便解码 XBRL 中的信息即可。
  • pd.read_xml()
    是正确的方法还是对于 XBRL 来说太有限了?我读到它可能太有限了,并且
    lxml
    提供了更多选项(尽管
    lxml
    pd.read_xml()
    的解析器。

我知道我不应该问广泛的、开放性的问题,所以我会更直接地问。

  • 以下说法正确吗?对我来说,XBRL 的逻辑似乎相当简单:有一个分类法,有一个数据文件,解析器需要能够使用分类法解释数据文件。
pandas xml xbrl
1个回答
0
投票

嗯,处理这些类型的文件确实很复杂。正如您所说,最好使用

lxml
库,与
pandas.read_xml()
相比,它提供了更多的多功能性。

  • 解决错误:

但是得到一个错误:XMLSyntaxError: Namespace prefix open on str is not 定义,第 16 行,第 51 列

根据 API 中数据的最小示例以及您在问题中显示的命名空间,我想说您缺少

open:str
标签的命名空间。这应该可以解决您在 MRE 中遇到的第一个错误:

from lxml import etree
import pandas as pd
from io import StringIO

xml = """
<xbrl 
    xml:lang="nl" 
    xmlns="http://www.xbrl.org/2003/instance" 
    xmlns:link="http://www.xbrl.org/2003/linkbase" 
    xmlns:xbrldi="http://xbrl.org/2006/xbrldi" 
    xmlns:xlink="http://www.w3.org/1999/xlink" 
    xmlns:iso4217="http://www.xbrl.org/2003/iso4217" 
    xmlns:dim="http://www.nbb.be/be/fr/cbso/dict/dim" 
    xmlns:open="http://www.example.com/open" ### Example of the missing part  
>
<link:schemaRef xlink:type="simple" xlink:href="http://www.nbb.be/be/fr/cbso/fws/23.0/mod/m87/m87-f.xsd"/>
<context id="c19">
<entity><identifier scheme="http://www.fgov.be">Some number</identifier></entity>
<period><instant>Some date</instant></period>
<scenario>
<xbrldi:typedMember dimension="dim:afnp"><open:str>John</open:str></xbrldi:typedMember>
<xbrldi:typedMember dimension="dim:annp"><open:str>Doe</open:str></xbrldi:typedMember>
<xbrldi:explicitMember dimension="dim:bas">bas:m31</xbrldi:explicitMember>
<xbrldi:explicitMember dimension="dim:ctc">ctc:m1</xbrldi:explicitMember>
<xbrldi:explicitMember dimension="dim:part">part:m2</xbrldi:explicitMember>
<xbrldi:explicitMember dimension="dim:psn">psn:m12</xbrldi:explicitMember>
</scenario>
</context>
</xbrl>"""

stringIO_xml = StringIO(xml)
tree = etree.parse(stringIO_xml)
root = tree.getroot()

namespaces = {
    'xbrl': 'http://www.xbrl.org/2003/instance',
    'xbrldi': 'http://xbrl.org/2006/xbrldi',
    'dim': 'http://www.nbb.be/be/fr/cbso/dict/dim',
    'open': 'http://www.example.com/open' ### Example of the missing part
}

然后,要访问

XPATH
的元素,您需要像这样进入树结构:

data = []
for context in root.findall('.//xbrl:context', namespaces):
    context_id = context.get('id')
    entity = context.find('.//xbrl:entity/xbrl:identifier', namespaces).text
    period = context.find('.//xbrl:period/xbrl:instant', namespaces).text
    scenario = context.find('.//xbrl:scenario', namespaces)
    
    row = {'context_id': context_id, 'entity': entity, 'period': period}
    
    for member in scenario.findall('.//xbrldi:typedMember', namespaces):
        dimension = member.get('dimension')
        value = member.find('.//open:str', namespaces).text
        row[dimension] = value
    
    for member in scenario.findall('.//xbrldi:explicitMember', namespaces):
        dimension = member.get('dimension')
        value = member.text
        row[dimension] = value
    
    data.append(row)

df = pd.DataFrame(data)

这将产生以下数据框: enter image description here

再次,我完成了您提供的示例,而不是压缩文件,这可能会导致其他问题,具体取决于 XML 结构的组成方式。不过,我想说,一旦将 XML 加载到字符串中,它应该非常简单。

© www.soinside.com 2019 - 2024. All rights reserved.