如何使用 BeautifulSoup 访问命名空间的 XML 元素?

Posted

技术标签:

【中文标题】如何使用 BeautifulSoup 访问命名空间的 XML 元素?【英文标题】:How can I access namespaced XML elements using BeautifulSoup? 【发布时间】:2011-03-04 18:54:19 【问题描述】:

我有一个这样的 XML 文档:

<xml>
<web:Web>
<web:Total>4000</web:Total>
<web:Offset>0</web:Offset>
</web:Web>
</xml>

我的问题是如何使用 Python 中的 BeautifulSoup 之类的库来访问它们?

xmlDom.web["Web"].Total ?不工作?

【问题讨论】:

BeautifulSoup = 4.6.1 (20180728) 后已过时 【参考方案1】:

BeautifulSoup 本身并不是一个 DOM 库(它没有实现 DOM API)。更复杂的是,您在该 xml 片段中使用命名空间。要解析特定的 XML 片段,您可以使用 BeautifulSoup,如下所示:

from BeautifulSoup import BeautifulSoup

xml = """<xml>
  <web:Web>
    <web:Total>4000</web:Total>
    <web:Offset>0</web:Offset>
  </web:Web>
</xml>"""

doc = BeautifulSoup( xml )
print doc.find( 'web:total' ).string
print doc.find( 'web:offset' ).string

如果您不使用命名空间,代码可能如下所示:

from BeautifulSoup import BeautifulSoup

xml = """<xml>
  <Web>
    <Total>4000</Total>
    <Offset>0</Offset>
  </Web>
</xml>"""

doc = BeautifulSoup( xml )
print doc.xml.web.total.string
print doc.xml.web.offset.string

这里的关键是 BeautifulSoup 对命名空间一无所知(或关心)。因此web:Web 被视为web:web 标记,而不是属于eweb 命名空间的Web 标记。虽然 BeautifulSoup 将 web:web 添加到 xml 元素字典中,但 python 语法不会将 web:web 识别为单个标识符。

您可以通过阅读documentation了解更多信息。

【讨论】:

谢谢!现在完美运行。我总是对给 find() 提供什么感到困惑。这些命名空间定义和它们的编写方式让我很困惑...任何清除所有这些的链接都将不胜感激! 只是我已经给你的文档链接......以及大量的实验。 AttributeError: 'NoneType' object has no attribute 'string'【参考方案2】:

这是一个老问题,但如果您将'xml' 作为第二个参数传递给构造函数,那么至少有人可能不知道BeautifulSoup 4 确实 可以很好地处理命名空间:

soup = BeautifulSoup("""<xml>
<web:Web>
<web:Total>4000</web:Total>
<web:Offset>0</web:Offset>
</web:Web>
</xml>""", 'xml')

print soup.prettify()
<?xml version="1.0" encoding="utf-8"?>
<xml>
 <Web>
  <Total>
   4000
  </Total>
  <Offset>
   0
  </Offset>
 </Web>
</xml>

【讨论】:

这对于 4.4.1-1 版本(在 ubuntu 64 16.04 中)并不完全正确。由于 cmets 是有限的。见link【参考方案3】:

您应该使用xmlns:prefix="URI"syntax (see examples here) 在根元素上明确定义您的命名空间,然后通过 BeautifulSoup 中的prefix:tag 访问您的属性。请记住,您还应该明确定义什么,BeautifulSoup 应该如何处理您的文档,在这种情况下:

xml = BeautifulSoup(xml_content, 'xml')

【讨论】:

【参考方案4】:

环境

import bs4
bs4.__version__
---
4.10.0'

import sys
print(sys.version)
---
3.8.10 (default, Nov 26 2021, 20:14:08) 
[GCC 9.3.0]

带有命名空间定义的 XML 上的 BS4/XML 解析器

from bs4 import BeautifulSoup

xbrl_with_namespace = """
<?xml version="1.0" encoding="UTF-8"?>
<xbrl
    xmlns:dei="http://xbrl.sec.gov/dei/2020-01-31"
>
<dei:EntityRegistrantName>
Hoge, Inc.
</dei:EntityRegistrantName>
</xbrl>
"""

soup = BeautifulSoup(xbrl_with_namespace, 'xml')
registrant = soup.find("dei:EntityRegistrantName")
print(registrant.prettify())
---
<dei:EntityRegistrantName>
Hoge, Inc.
</dei:EntityRegistrantName>

没有命名空间定义的 XML 上的 BS4/XML 解析器

xbrl_without_namespace = """
<?xml version="1.0" encoding="UTF-8"?>
<dei:EntityRegistrantName>
Hoge, Inc.
</dei:EntityRegistrantName>
</xbrl>
"""

soup = BeautifulSoup(xbrl_without_namespace, 'xml')
registrant = soup.find("dei:EntityRegistrantName")
print(registrant)
---
None

没有命名空间定义的 XML 上的 BS4/html 解析器

BS4/HTML 解析器将&lt;namespace&gt;:&lt;tag&gt; 视为单个标签,除此之外它还降低了字母。

soup = BeautifulSoup(xbrl_without_namespace, 'html.parser')
registrant = soup.find("dei:EntityRegistrantName".lower()) 

print(registrant)
---
<dei:entityregistrantname>
Hoge, Inc.
</dei:entityregistrantname>

与大写字母不匹配,因为它们已被转换为小写字母。

registrant = soup.find("dei:EntityRegistrantName") 
print(registrant)
---
None

结论

    提供命名空间定义以将命名空间与 XML 解析器一起使用,或者 使用 HTML 解析器并处理所有小写字母。

【讨论】:

以上是关于如何使用 BeautifulSoup 访问命名空间的 XML 元素?的主要内容,如果未能解决你的问题,请参考以下文章

BeautifulSoup.find_all() 方法不适用于命名空间标签

C++命名空间成员访问不同文件如何? “命名空间标准”是如何实现的?

如何防止从命名空间内访问类?

如何访问 Windows.Storage 命名空间?

C#中如何获得指定命名空间中所有自定义类的信息

js单例——如何避免通过命名空间访问类成员