使用lxml重复XML元素

时间:2019-10-16 08:11:08

标签: python xml lxml

我必须创建一个XML文档,该文档必须具有在不同部分重复的相同信息。我正在创建一些details作为etree.Element并将其附加到几个辅助XML元素上

from lxml import etree

top = etree.Element('Primary')
element1 = etree.Element('Secondary')
element2 = etree.Element('Secondary')

details = etree.Element('Details', somevalue='value')

element1.append(details)
element2.append(details)
top.append(element1)
top.append(element2)

print(etree.tostring(top, encoding="unicode", pretty_print=True))

我想要的输出是;

<Primary>
  <Secondary>
    <Details somevalue="value"/>
  </Secondary>
  <Secondary>
    <Details somevalue="value"/>
  </Secondary>
</Primary>

我得到的输出是;

<Primary>
  <Secondary/>
  <Secondary>
    <Details somevalue="value"/>
  </Secondary>
</Primary>

lxml似乎只将details元素放在一个位置。有什么办法可以关闭它吗?

谢谢!

2 个答案:

答案 0 :(得分:2)

以下内容摘自lxml documentation

  

请注意,在原始ElementTree中,可以放置一个Element对象   在任何数量的树木中的任何数量的地方,这允许   与列表相同的复制操作。明显的缺点是   对此类元素的修改将应用于该元素的所有位置   出现在树上,这可能是预期的,也可能不是预期的。

     

这种区别的好处是lxml.etree中的Element总是   仅有一个父对象,可以通过getparent()查询   方法。原始ElementTree不支持此功能。

因此,与ElementTree中的原始元素不同,lxml中的一个元素只能具有一个父元素。因此,不可能仅使用lxml将同一元素附加到多个父对象。但是,文档建议处理这种新设计,如果已将其分配给其他元素,则应使用深层复制将要附加的元素复制到另一个元素。

这将创建该元素的新副本,因此可以将该新副本分配给其他父元素。这些是单独的副本,因此更改一个不会更改另一个。

from lxml import etree
from copy import deepcopy

top = etree.Element('Primary')
element1 = etree.Element('Secondary')
element2 = etree.Element('Secondary')
details = etree.Element('Details', somevalue='value')
element1.append(details)
element2.append(deepcopy(details))
top.append(element1)
top.append(element2)
print(etree.tostring(top, encoding="unicode", pretty_print=True))

输出

<Primary>
  <Secondary>
    <Details somevalue="value"/>
  </Secondary>
  <Secondary>
    <Details somevalue="value"/>
  </Secondary>
</Primary>

已更新杰克示例

因此,在杰克的示例中,我设置了一个变量num_secondarys,该变量将创建X个次要元素,每个元素都包含一个detail元素,并且detail元素中的值将增加1。模板,然后使用Deepcopy将其复制为新元素。

from lxml import etree
from copy import deepcopy

top = etree.Element('Primary')
secondary = etree.Element('Secondary')
detail = etree.Element('Details', somevalue='value')
num_secondarys = 3
for i in range(1, num_secondarys + 1):
    this_secondary = deepcopy(secondary)
    this_detail = deepcopy(detail)
    this_detail.attrib['somevalue']+=str(i)
    this_secondary.append(this_detail)
    top.append(this_secondary)

print(etree.tostring(top, encoding="unicode", pretty_print=True))

输出

<Primary>
  <Secondary>
    <Details somevalue="value1"/>
  </Secondary>
  <Secondary>
    <Details somevalue="value2"/>
  </Secondary>
  <Secondary>
    <Details somevalue="value3"/>
  </Secondary>
</Primary>

答案 1 :(得分:0)

下面(使用ElementTree内置的python XML库)

import xml.etree.ElementTree as ET

root = ET.Element('Primary')
for x in range(2):
  sec = ET.SubElement(root, 'Secondary')
  details = ET.Element('Details')
  details.attrib['somevalue'] = 'value'
  sec.append(details)
ET.dump(root)

输出

<Primary>
   <Secondary>
      <Details somevalue="value" />
   </Secondary>
   <Secondary>
      <Details somevalue="value" />
   </Secondary>
</Primary>