背景:我正在尝试使用从Web服务端点检索的元数据来充实XML报告。该报告列出了文本模块和图形,每个图形都有几种分辨率。我无法为每个分辨率添加元数据。
问题:这是简化的问题。
from lxml import etree as ET
myxml = """\
<report>
<object id="foo">
<reportitems>
<reportitem id="1"/>
<reportitem id="2"/>
<reportitem id="3"/>
</reportitems>
</object>
</report>
"""
report = ET.fromstring(myxml)
test = ET.Element("test", foo="bar")
for r in report.findall("object/reportitems/reportitem"):
r.append(test)
我得到了这个输出:
<report>
<object id="foo">
<reportitems>
<reportitem id="1"/>
<reportitem id="2"/>
<reportitem id="3"><test foo="bar"/></reportitem>
</reportitems>
</object>
</report>
现在,如果我像这样修改代码(使用相同的XML代码段):
report = ET.fromstring(myxml)
myElements = [ET.Element("test1"), ET.Element("test2"), ET.Element("test3")]
counter = 0
for r in report.findall("object/reportitems/reportitem"):
r.append(myElements[counter])
counter += 1
...然后我得到了这个输出:
<report>
<object id="foo">
<reportitems>
<reportitem id="1"><test1/></reportitem>
<reportitem id="2"><test2/></reportitem>
<reportitem id="3"><test3/></reportitem>
</reportitems>
</object>
</report>
为什么我不能将与孩子相同(相同)的元素添加到我迭代的多个元素中?
答案 0 :(得分:4)
还有另一个重要的案例,即Elements中的行为 lxml(在2.0及更高版本中)与列表和列表的不同 原始的ElementTree(1.3版之前或Python 2.7 / 3.2之前):
>>> for child in root:
... print(child.tag)
child0 child1 child2 child3
>>> root[0] = root[-1] # this moves the element in lxml.etree!
>>> for child in root:
... print(child.tag)
child3 child1 child2
在此示例中,最后一个元素被移动到不同的位置, 而不是被复制,即它自动从其中删除 将它放在不同的地方以前的位置。在列表中 对象可以同时出现在多个位置,而且 上面的赋值只会将项目引用复制到第一个 位置,以便两者包含完全相同的项目:
>>> l = [0, 1, 2, 3]
>>> l[0] = l[-1]
>>> l
[3, 1, 2, 3]
请注意,在原始的ElementTree中,单个Element对象可以位于任意数量树中的任意数量的位置, 它允许与列表相同的复制操作。显而易见的 缺点是对这种元素的修改将适用于所有人 它出现在树中的地方,可能是也可能不是。 这种差异的好处是lxml.etree中的元素总是如此 只有一个父,可以通过getparent()查询 方法。原始的ElementTree不支持此功能。
>>> root is root[0].getparent() # lxml.etree only!
True
如果要将元素复制到lxml.etree中的其他位置,请考虑 使用Python的复制模块创建独立的深层副本 标准库:
>>> from copy import deepcopy
>>> element = etree.Element("neu")
>>> element.append( deepcopy(root[1]) )
>>> print(element[0].tag)
child1
>>> print([ c.tag for c in root ])
['child3', 'child1', 'child2']
答案 1 :(得分:0)
构造函数ET.Element
中的问题每次调用只创建一个节点。您可以更改节点的父节点,但ET.Element
将只有一个节点。您可以在循环中多次创建ET.Element
以避免此问题:
for r in report.findall("object/reportitems/reportitem"):
node = ET.Element("test", foo="bar")
r.append(node)