3

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

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元素而不明确指定其命名空间,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 都是一样的,不管我用的xml.dom.createElement()xml.dom.createElementNS(). 如果这是一个错误,那么它在哪里?在xml.dom还是在xpath

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

4

1 回答 1

2

简要地:

问题是:这种行为是正确的还是一个错误?

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

的命名空间不应该Chimp是隐式的吗?

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

毕竟生成的 XML 都是一样的,不管我用的xml.dom.createElement()xml.dom.createElementNS().

生成的 XML 不一样,或者至少不应该一样。

如果这是一个错误,那么它在哪里?

我猜该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元素继承与第一个元素相同的(默认)命名空间,因此您的第三个 find 返回 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 尽管它的状态,它实际上仍然是开放的,因为它作为另一个开放错误的副本被关闭。

于 2014-01-20T13:50:31.333 回答