【发布时间】:2022-12-03 00:43:34
【问题描述】:
我想创建一个 XML 命名空间映射(例如,在 findall 调用中使用,就像在 the Python documentation of ElementTree 中一样)。鉴于定义似乎作为 xbrl 根元素的属性存在,我想我可以检查我的 root 元素中的 attrib 属性ElementTree。然而,下面的代码
from io import StringIO
import xml.etree.ElementTree as ET
TEST = '''<?xml version="1.0" encoding="utf-8"?>
<xbrl
xml:lang="en-US"
xmlns="http://www.xbrl.org/2003/instance"
xmlns:country="http://xbrl.sec.gov/country/2021"
xmlns:dei="http://xbrl.sec.gov/dei/2021q4"
xmlns:iso4217="http://www.xbrl.org/2003/iso4217"
xmlns:link="http://www.xbrl.org/2003/linkbase"
xmlns:nvda="http://www.nvidia.com/20220130"
xmlns:srt="http://fasb.org/srt/2021-01-31"
xmlns:stpr="http://xbrl.sec.gov/stpr/2021"
xmlns:us-gaap="http://fasb.org/us-gaap/2021-01-31"
xmlns:xbrldi="http://xbrl.org/2006/xbrldi"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
</xbrl>'''
xbrl = ET.parse(StringIO(TEST))
print(xbrl.getroot().attrib)
产生以下输出:
{'{http://www.w3.org/XML/1998/namespace}lang': 'en-US'}
为什么root.attrib 中没有显示任何名称空间属性?我至少希望 xlmns 出现在字典中,因为它没有前缀。
我尝试了什么?
以下代码似乎可以生成名称空间映射:
print({prefix: uri for key, (prefix, uri) in ET.iterparse(StringIO(TEST), events=['start-ns'])})
输出:
{'': 'http://www.xbrl.org/2003/instance',
'country': 'http://xbrl.sec.gov/country/2021',
'dei': 'http://xbrl.sec.gov/dei/2021q4',
'iso4217': 'http://www.xbrl.org/2003/iso4217',
'link': 'http://www.xbrl.org/2003/linkbase',
'nvda': 'http://www.nvidia.com/20220130',
'srt': 'http://fasb.org/srt/2021-01-31',
'stpr': 'http://xbrl.sec.gov/stpr/2021',
'us-gaap': 'http://fasb.org/us-gaap/2021-01-31',
'xbrldi': 'http://xbrl.org/2006/xbrldi',
'xlink': 'http://www.w3.org/1999/xlink',
'xsi': 'http://www.w3.org/2001/XMLSchema-instance'}
但是,哎呀,不得不两次解析文件是不是很恶心。
【问题讨论】:
-
诸如
xmlns="http://www.w3.org/2000/svg"之类的命名空间声明在语法上是一个属性。但是正如您所注意到的,它不是解析 XML 文档时创建的数据结构中的属性。 XML 信息集规范将属性和名称空间定义为单独的“信息项”:en.wikipedia.org/wiki/XML_Information_Set。另见rpbourret.com/xml/NamespacesFAQ.htm#decl。 -
但是你不只需要提取一次名称空间吗?如果您事先不知道稍后将在 xpath 中使用“nvda:whatever”,为什么还要费心将
xmlns:nvda="http://www.nvidia.com/20220130"添加到名称空间映射?你可以做一次 iterparse 的事情作为一种简单的方法来为这种类型的文档获取一个命名空间字典,然后根据需要将它复制到你的脚本中。更一般地说,名称空间通常暗示您必须了解的模式才能知道要搜索哪种类型的东西。名称空间字典似乎只是其中的一小部分。 -
lxml将在元素上包含一个nsmap,因此您可以更改为使用不同的工具集。命名空间可以在任何元素上声明,因此您仍然需要扫描。 -
@tdelaney 我知道我正在搜索
nvda:whatever,但 uris 以不同的频率变化(nvda,大约每季度一次)。例如,在下一季度的财务结果中,xmlns:nvda="http://www.nvidia.com/20220430"。感觉就像我必须更改每个财务报告的硬编码命名空间映射,即使我知道我一直在寻找nvda:units。 -
命名空间应该很少更改……仅当该命名空间的模式发生更改时。可能添加或删除了字段。我有点惊讶这些看起来比较新。我离开 XML 业务已有一段时间了,但对于我正在从事的工作,模式 URI 更改是一个值得注意的事件。我很想跟踪当前模式,如果脚本未能正确扫描 xml,则查找更改。不过,在所有情况下可能都不是令人满意的解决方案。
标签: python xml elementtree xml-namespaces