python lxml objectify скопировать элемент со всеми субэлементами
Есть файл формата XML, в нем, в корне есть много дочерних элементов, которые имеют атрибуты и свои дочерние элементы. Необходимо скопировать один корневой дочерний элемент и добавить эту копию с измененными атрибутами.
Из
<?xml version="1.0" encoding="utf-8"?>
<config FS_Version="3.1.3.0" CurrentDateTime="10.09.2020 20:38:36" DateTimeISO="2020-09-10T20:38:36.789+05:00">
<drv idx="0" name="Компьютер"/>
<drv idx="1" name="Удаленный сервер"/>
<zone idx="0" no="101" GUID="{858BD75D4FA}" name="zone1" idZones="0">
<param name="ZoneType" type="Int" value="1"/>
<param name="Category" type="Byte" value="0"/>
</zone>
<zone idx="1" no="102" GUID="{4B7FFE8665A}" name="zone2" idZones="0">
<param name="ZoneType" type="Int" value="1"/>
<param name="Category" type="Byte" value="0"/>
</zone>
</config>
Получить:
<?xml version="1.0" encoding="utf-8"?>
<config FS_Version="3.1.3.0" CurrentDateTime="10.09.2020 20:38:36" DateTimeISO="2020-09-10T20:38:36.789+05:00">
<drv idx="0" name="Компьютер"/>
<drv idx="1" name="Удаленный сервер"/>
<zone idx="0" no="101" GUID="{858BD75D4FA}" name="zone1" idZones="0">
<param name="ZoneType" type="Int" value="1"/>
<param name="Category" type="Byte" value="0"/>
</zone>
<zone idx="1" no="102" GUID="{4B7FFE8665A}" name="zone2" idZones="0">
<param name="ZoneType" type="Int" value="1"/>
<param name="Category" type="Byte" value="0"/>
</zone>
<zone idx="2" no="103" GUID="{}" name="newZone" idZones="0">
<param name="ZoneType" type="Int" value="1"/>
<param name="Category" type="Byte" value="0"/>
</zone>
</config>
То есть один-в-один скопировать элемент с тегом zone, изменив только атрибуты.
Понимаю, что можно составить элемент заново, но полагаю есть метод позволяющий просто его скопировать. Хотелось бы что-то типа
from lxml import etree as et, objectify as objtf
with open('file.xml', encoding='utf-8') as fobj:
xml = fobj.read()
root = objtf.fromstring(xml)
newZ = root.zone[0]
newZ.set('name', 'newZone')
newZ.set('GUID', '')
newZ.set('no', '103')
newZ.set('idx', '2')
root.zone = newZ
Таким макаром запись добавляется, но вместе с тем меняется и исходная.
Ответы (1 шт):
Нашел ответ на англоязычном stackoverflow - etree Clone Node
Замечательно работает этот вариант с copy.deepcopy() от пользователя Steven.
Следующий код решил поставленную задачу:
newZ = copy.deepcopy(root.zone[0])
newZ.set('name', 'newZone')
newZ.set('GUID', '')
newZ.set('no', '103')
newZ.set('idx', '2')
root.append(newZ)