【发布时间】:2021-12-21 14:32:00
【问题描述】:
from lxml import etree
element1 = etree.Element('{j:a}a', nsmap={None: 'j:a'})
etree.SubElement(element1, 'b')
element2 = etree.Element('{j:a}a', nsmap={None: 'j:a'})
etree.SubElement(element2, '{j:a}b')
两个元素都序列化为相同的
<a xmlns="j:a"><b/></a>
但两个元素不表现相同
element1.find('b') -> 返回元素
element2.find('b') -> 返回无
如果你反其道而行之
etree.fromstring("<a xmlns="j:a"><b/></a>")
你从 element2 得到表示,所以
element2.find('b') -> 返回无
这似乎是一致的,因为树中没有无命名空间的<b/>,因为<b/> 从<a/> 继承了默认命名空间
那么在 element1 中表示的目的是什么?它似乎添加了一个无命名空间的子元素 <b/> 并以这种方式运行。但是当序列化时,元素继承自<a>。
如果它无论如何都不序列化,为什么会存在?
【问题讨论】:
-
你使用的是哪个lxml版本?
-
lxml 版本为 4.6.3
-
您认为 lxml 不应该允许的究竟是什么?你期待什么?
-
@mzjn 预期的行为是所有未指定自己的命名空间的元素都将继承在其位置有效的默认命名空间。这就是 lxml 的文档解析的工作方式(根据规范),但它不是 lxml 的文档生成的工作方式。这至少是“令人惊讶的 API 行为”,它会生成不存在且行为不正常的文档树。在我的书中,这被认为是一个错误。
-
@mzjn 这当然是在这个问题上的一个立场,但我认为这是从“API 实现者的便利”的角度来看的。这样做当然更容易。但是元素要么在命名空间中,要么不在。没有歧义需要解决。在第一种情况下,正确的做法是生成
<a xmlns="j:a"><b xmlns="" /></a>。这将是一致的,它会生成一个合法的 XML 树,它在解析后会表现相同,并且它会立即表明 API 需要像.SubElement(element2, '{j:a}b')中的显式命名空间。
标签: python xml lxml xml-namespaces