1

我是堆栈溢出的新手,所以对每个人都“嗨”,我希望有人可以帮助我解决我的问题......

最近我开始玩弄 lxml.objectify 并偶然发现以下行为,我发现这很奇怪。如果我只是创建一个像这样的小 xml 字符串:

from lxml import objectify 

objroot = objectify.fromstring("<root>somerootvalue<child1/><child2/><child3/><child4><subchild1/><subchild2/></child4><child5><subchild1/><subchild2/></child5></root>")
objroot.child4 = True
objroot.child4.subchild1 = "Foo"
objroot.child4.subchild2 = "Bar"
print(objroot.child4.subchild1,objroot.child4.subchild2,objroot.child4)

输出只是: Foo Bar true

如果我更改元素的值/文本,则通过:

from lxml import objectify 

objroot = objectify.fromstring("<root>somerootvalue<child1/><child2/><child3/><child4><subchild1/><subchild2/></child4><child5><subchild1/><subchild2/></child5></root>")
objroot.child4 = True
objroot.child4.subchild1 = "Foo"
objroot.child4.subchild2 = "Bar"
print(objroot.child4.subchild1,objroot.child4.subchild2,objroot.child4)
objroot.child4 = False
objroot.child4.subchild1 = "Foo"
objroot.child4.subchild2 = "Bar"
print(objroot.child4.subchild1,objroot.child4.subchild2,objroot.child4)

输出如预期:Foo Bar true, Foo Baz false

但是,如果我只是更改 objroot.child4 的值并调用 print 语句,则会出现以下错误:

from lxml import objectify 

objroot = objectify.fromstring("<root>somerootvalue<child1/><child2/><child3/><child4><subchild1/><subchild2/></child4><child5><subchild1/><subchild2/></child5></root>")
objroot.child4 = True
objroot.child4.subchild1 = "Foo"
objroot.child4.subchild2 = "Bar"
print(objroot.child4.subchild1,objroot.child4.subchild2,objroot.child4)
objroot.child4 = False
objroot.child4.subchild1 = "Foo"
objroot.child4.subchild2 = "Bar"
print(objroot.child4.subchild1,objroot.child4.subchild2,objroot.child4)
objroot.child4 = True
print(objroot.child4.subchild1,objroot.child4.subchild2,objroot.child4)
File "src\lxml\lxml.objectify.pyx", line 450, in lxml.objectify._lookupChildOrRaise (src\lxml\lxml.objectify.c:6586)
AttributeError: no such child: subchild1

虽然我希望最后一个输出是“Foo Bar true”,但我得到了“没有这样的子错误”。那么看来child4后面那棵树的剩余部分已经被砍掉了?这是一种理想的行为吗?如果是的话,我怎样才能在不剪切其余部分的情况下更改树中间元素的文本?

谢谢您的帮助!

4

1 回答 1

1

一旦我们深入研究它,实际上并没有那么奇怪的行为。使用root.element.subelement....并没有像您想象的那样执行。我们可以使用etree打印出 xml 树的状态并检查结构。

from lxml import objectify, etree

objroot = objectify.fromstring("<root>somerootvalue<child1/><child2/><child3/><child4><subchild1/><subchild2/></child4><child5><subchild1/><subchild2/></child5></root>")

print(etree.tostring(objroot, pretty_print=True)

#output:
<root>somerootvalue
    <child1/>
    <child2/>
    <child3/>
    <child4><subchild1/><subchild2/></child4>
    <child5><subchild1/><subchild2/></child5>
</root>

这看起来是正确的。那么当我们调用时会发生什么objroot.child4 = True?API 允许您执行此操作,但它不只是添加文本。相反,它用child4文本替换了下面的所有内容。所以子元素被删除。我们可以检查使用:

objroot.child4 = True
print(etree.tostring(objroot, pretty_print=True)

#output:
<root>somerootvalue
    <child1/>
    <child2/>
    <child3/>
    <child4 xmlns:py="..." py:pytype="bool">true</child4>
    <child5><subchild1/><subchild2/></child5>
</root>

所以它设置了child4to的值True,但它已经删除了子元素。之后,当您使用以下方法设置子元素的值时:

objroot.child4.subchild1 = "Foo"
objroot.child4.subchild2 = "Bar"

它实际上在下面创建每个子元素child4,然后动态设置值。

于 2016-08-29T17:02:31.690 回答