在 python lxml 中设置和访问命名空间

Setting and accessing namespaces in python lxml

我正在编写一个脚本来处理 rdf:skos 包含 python3 和 lxml 的文件:

我了解到我需要将 XML 提到的名称空间传递给 findall 过程。 (好吧,奇怪,因为 XML 文件在 header 中列出了这些,所以这似乎是一个不必要的步骤,但无论如何)。

调用时

for concept in root.findall('.//skos:Concept', namespaces=root.nsmap):

有效,因为 root.nsmap 是由 lxml 构造的。

但是稍后在我的代码中我还需要对 xml:lang

执行测试
for pl in concept.findall(".//skos:prefLabel[@xml:lang='en']", namespaces=root.nsmap):

这里 python 告诉我

SyntaxError: prefix 'xml' not found in prefix map

好的,没错,在我的 skos 文件中没有对 xml 命名空间的额外声明。所以我尝试将它添加到 root.nsmap dict

root.nsmap['xml'] = "http://www.w3.org/XML/1998/namespace"

但这也行不通

nsmap = {'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'uneskos': 'http://purl.org/umu/uneskos#', 'iso-thes': 'http://purl.org/iso25964/skos-thes#', 'dcterms': 'http://purl.org/dc/terms/', 'skos': 'http://www.w3.org/2004/02/skos/core#', 'rdfs': 'http://www.w3.org/2000/01/rdf-schema#'}

好像不允许我修改root.nsmap

有人知道这是怎么做到的吗?我过去用 Perl XML::Twig 处理过大量 XML,这非常非常舒服,我相信 Python 社区有(至少)类似的舒适方式来做到这一点......但是怎么办?

感谢任何提示。

修改root.nsmap无效。但是您可以创建另一个字典并修改那个字典。示例:

from lxml import etree

doc = """
<root xmlns:skos="http://www.w3.org/2004/02/skos/core#">
   <skos:prefLabel xml:lang='en'>FOO</skos:prefLabel>
   <skos:prefLabel xml:lang='de'>BAR</skos:prefLabel>
</root>"""

root = etree.fromstring(doc)
nsmap = root.nsmap
nsmap["xml"] = "http://www.w3.org/XML/1998/namespace" 

en = root.find(".//skos:prefLabel[@xml:lang='en']", namespaces=nsmap)
print(en.text)

输出:

FOO