Python:如果在没有命名空间的情况下添加新元素,则 xpath.find() 将找不到新元素

标签 python xml xpath python-2.7 xml-namespaces

今天我偶然发现了 xml.domxpath 模块的一种特殊行为,我花了一段时间才弄清楚它与 XML namespace 有关:

from xml.dom import minidom
import xpath

zooXml = """<?xml version="1.0" encoding="utf-8"?>
<Zoo xmlns='http://foo.bar/zoo'>
  <Compound><Chimp/></Compound>
</Zoo>"""

mydom = minidom.parseString(zooXml)
compound = xpath.findnode('/Zoo/Compound', mydom)
print compound.toxml() # as expected: <Compound><Chimp/></Compound>
print xpath.find("Chimp", compound) # as expected: [<DOM Element: Chimp at 0x24c0cc8>]

到目前为止一切顺利,但如果我现在添加另一个 Chimp 元素而不明确指定其 namespace ,xpath 将找不到新元素:

newChimp = mydom.createElement("Chimp")
compound.appendChild(newChimp)
print compound.toxml() # ok, two chimps now: <Compound><Chimp/><Chimp/></Compound>
print xpath.find("Chimp", compound) # wait a second, that's still only one chimp: [<DOM Element: Chimp at 0x24a0d88>]

重新解析修改后的XML后,xpath会找到这两个元素:

mydom = minidom.parseString(mydom.toxml())
compound = xpath.findnode('/Zoo/Compound', mydom)
print xpath.find("Chimp", compound) # now it finds both chimps: [<DOM Element: Chimp at 0x24c9808>, <DOM Element: Chimp at 0x24c9888>]

此外,如果我使用命名空间创建新元素,xpath 将在不重新解析的情况下找到它们:

babyChimp = mydom.createElementNS(mydom.firstChild.namespaceURI, "Chimp")
compound.appendChild(babyChimp)
print xpath.find("Chimp", compound) # that worked: [<DOM Element: Chimp at 0x24c9808>, <DOM Element: Chimp at 0x24c9888>, <DOM Element: Chimp at 0x24c9548>]

问题是:这种行为是正确的还是错误? Chimp 的命名空间不应该是隐式的吗?毕竟,无论我使用 xml.dom.createElement() 还是 xml.dom.createElementNS(),生成的 XML 都是一样的。如果这是一个错误,那么它在哪里?在 xml.domxpath 中?

FWIW:我在 Python 2.7.5 和 2.7.4 的 Windows 发行版中观察到了这种行为,在这两种情况下我都使用了 xpath。模块 0.1。

最佳答案

简要说明:

The question is: is this behaviour correct or is it a bug?

该行为似乎不正确或至少是不需要的,所以我会说它是错误或未完成的功能。

Shouldn't the namespace of Chimp be implicit?

在解析字符串时它是隐式的,但在创建该元素并将该元素添加到树时它不是隐式的。

After all, the XML generated will be the same, regardless of whether I use xml.dom.createElement() or xml.dom.createElementNS().

生成的 XML 不相同,或者至少不应该相同。

And if this is a bug, then where is it?

我猜 toxml() 方法中存在错误,它不输出第二个 Chimp 元素的空默认命名空间,因此它继承了重新解析修改后的文档时 Zoo 元素的默认命名空间。

更准确地说:

首先你的文档是

<Zoo xmlns='http://foo.bar/zoo'>
  <Compound><Chimp/></Compound>
</Zoo>

然后您尝试找到 Chimp 元素,但您没有为它定义任何命名空间上下文。然而,在这种情况下,xpath 模块似乎从节点的文档元素初始化上下文,因此查找成功。

然后您添加另一个 Chimp 元素,但没有命名空间,您的文档变为

<Zoo xmlns='http://foo.bar/zoo'>
  <Compound><Chimp/><Chimp xmlns=""/></Compound>
</Zoo>

第二次查找尝试仅返回一个元素,因为另一个具有不同的命名空间。

我猜这个错误发生在这里,而不是上面的正确版本,toxml() 方法的输出实际上是

<Zoo xmlns='http://foo.bar/zoo'>
  <Compound><Chimp/><Chimp/></Compound>
</Zoo>

重新解析该文本会导致第二个 Chimp 元素继承与第一个元素相同的(默认)命名空间,因此您的第三个查找返回 2 个元素。

添加最后一个 Chimp 元素会使文档变成

<Zoo xmlns='http://foo.bar/zoo'>
  <Compound><Chimp/><Chimp/><Chimp xmlns='http://foo.bar/zoo'/></Compound>
</Zoo>

完全一样

<Zoo xmlns='http://foo.bar/zoo'>
  <Compound><Chimp/><Chimp/><Chimp/></Compound>
</Zoo>

同样,所有 Chimp 元素都在同一个命名空间中,因此 find 会返回它们。

这个错误似乎是相关的:http://bugs.python.org/issue1371937尽管它处于状态,但它实际上仍然处于打开状态,因为它作为另一个打开的错误的副本而关闭。

关于Python:如果在没有命名空间的情况下添加新元素,则 xpath.find() 将找不到新元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16980521/

相关文章:

python - 在 SpaCy 中使用 REGEX 和 ORTH 作为短语匹配的一部分

xml - 如何正确解析xml

xml - XSL 和 XPATH 问题匹配

python - 如何从外部文件中列出 python 中的数字?

python - 如果第一个数字和长度相同,则从列表中删除数字

android - 无法使评级栏与 TextView 对齐

android - 按钮应该粘在底部,带有 adjustResize

java - 在java代码中使用xpath时出错

javascript - 如何迭代 ORDERED_NODE_SNAPSHOT_TYPE 类型的 javascript XPathResult

python - 属性错误 : module 'tkinter' has no attribute 'tk'