Lxml元素与名称空间的相等性

mjn*_*n12 8 python lxml xml-namespaces

我试图使用Lxml来解析.docx文档的内容.我知道lxml将命名空间前缀替换为实际的命名空间,但是这使得检查我正在使用的元素标记类型真的很痛苦.我希望能够做类似的事情

if (someElement.tag == "w:p"):
Run Code Online (Sandbox Code Playgroud)

但由于lxml坚持预先设置te ful命名空间,我要么必须做类似的事情

if (someElemenet.tag == "{http://schemas.openxmlformats.org/wordprocessingml/2006/main}p'):
Run Code Online (Sandbox Code Playgroud)

或者像这样从元素的nsmap属性中查找完整的命名空间名称

targetTag = "{%s}p" % someElement.nsmap['w']
if (someElement.tag == targetTag):
Run Code Online (Sandbox Code Playgroud)

如果有一种更容易的方法来说服lxml

  1. 给我标签字符串没有附加名称空间,我可以使用prefix属性和这些信息来检查我正在使用哪个标签或
  2. 只需使用前缀给我标记字符串

在编写此解析器时,这将节省大量的击键次数.这可能吗?我在文档中遗漏了什么吗?

unu*_*tbu 22

也许使用local-name():

import lxml.etree as ET
tree = ET.fromstring('<root xmlns:f="foo"><f:test/></root>')
elt=tree[0]
print(elt.xpath('local-name()'))
# test
Run Code Online (Sandbox Code Playgroud)


sam*_*ias 5

我找不到从元素中获取非命名空间标记名称的方法 - lxml认为标记名称的完整命名空间部分.以下是一些可能有用的选项..

您还可以使用QName该类来构造用于比较的命名空间标记:

import lxml.etree
from lxml.etree import QName

tree = lxml.etree.fromstring('<root xmlns:f="foo"><f:test/></root>')
qn = QName(tree.nsmap['f'], 'test')
assert tree[0].tag == qn
Run Code Online (Sandbox Code Playgroud)

如果您需要裸标签名称,则必须编写实用程序函数来提取它:

def get_bare_tag(elem):
    return elem.tag.rsplit('}', 1)[-1]

assert get_bare_tag(tree[0]) == 'test'
Run Code Online (Sandbox Code Playgroud)

不幸的是,据我所知,你不能{*}test使用lxml的xpath/find方法搜索带有"any namespace"的标签(例如).

更新:请注意,lxml不会构造仅包含的标记{ or }- 它将引发ValueError:无效的标记名称,因此可以安全地假设标记名称以其开头的元素{是平衡的.

lxml.etree.Element('{foo')
ValueError: Invalid tag name
Run Code Online (Sandbox Code Playgroud)

  • +1表示建议QName类.至于获取本地名称(如果你真的必须),你可以使用xpath:`elem.xpath('local-name()')` (3认同)

GPH*_*ley 5

etree.Qname 应该能够为您带来想要的东西。

from lxml import etree

# [...]

tag = etree.QName(someElement)

print(tag.namespace, tag.localname)
Run Code Online (Sandbox Code Playgroud)

对于您的示例标记,将输出:

http://schemas.openxmlformats.org/wordprocessingml/2006/main p
Run Code Online (Sandbox Code Playgroud)

请注意,QName它将采用Element对象或字符串(例如from Element.tag)。

并且,如您所述,还可以使用Element.nsmap从任意前缀映射到名称空间。

所以像这样:

if tag.namespace == someElement.nsmap["w"] and tag.localname == "p":
Run Code Online (Sandbox Code Playgroud)