etree Clone Node
Question:
How to clone Element
objects in Python xml.etree
? I’m trying to procedurally move and copy (then modify their attributes) nodes.
Answers:
If you have a handle on the Element
elem
‘s parent
you can call
new_element = SubElement(parent, elem.tag, elem.attrib)
Otherwise you might want to try
new_element = makeelement(elem.tag, elem.attrib)
but this is not advised.
You can just use copy.deepcopy() to make a copy of the element. (this will also work with lxml by the way).
A different, and somewhat disturbing solution:
new_element = lxml.etree.fromstring(lxml.etree.tostring(elem))
At least in Python 2.7 etree Element has a copy method:
http://hg.python.org/cpython/file/2.7/Lib/xml/etree/ElementTree.py#l233
It is a shallow copy, but that is preferable in some cases.
In my case I am duplicating some SVG Elements and adding a transform. Duplicating children wouldn’t serve any purpose since where relevant they already inherit their parent’s transform.
For future reference.
Simplest way to copy a node (or tree) and keep it’s children, without having to import ANOTHER library ONLY for that:
def copy_tree( tree_root ):
return et.ElementTree( tree_root );
duplicated_node_tree = copy_tree ( node ); # type(duplicated_node_tree) is ElementTree
duplicated_tree_root_element = new_tree.getroot(); # type(duplicated_tree_root_element) is Element
If you procedurally move through your tree with loops, you can use insert
to clone directly ( insert(index, subelement)
) and tree indexing (both in the documentation):
import xml.etree.ElementTree as ET
mytree = ET.parse('some_xml_file.xml') # parse tree from xml file
root = mytree.getroot() # get the tree root
for elem in root: # iterate over children of root
if condition_for_cloning(elem) == True:
elem.insert(len(elem), elem[3]) # insert the 4th child of elem to the end of the element (clone an element)
or for children with some tag:
for elem in root:
children_of_interest = elem.findall("tag_of_element_to_clone")
elem.insert(len(elem), children_of_interest[1])
For anyone visiting from the future:
If you want to clone the entire element, use append
.
new_tree = ET.Element('root')
for elem in a_different_tree:
new_tree.append(elem)
@dennis-williamson made a comment about it which I overlooked and eventually stumbled on the answer here https://stackoverflow.com/a/6533808/4916945
How to clone Element
objects in Python xml.etree
? I’m trying to procedurally move and copy (then modify their attributes) nodes.
If you have a handle on the Element
elem
‘s parent
you can call
new_element = SubElement(parent, elem.tag, elem.attrib)
Otherwise you might want to try
new_element = makeelement(elem.tag, elem.attrib)
but this is not advised.
You can just use copy.deepcopy() to make a copy of the element. (this will also work with lxml by the way).
A different, and somewhat disturbing solution:
new_element = lxml.etree.fromstring(lxml.etree.tostring(elem))
At least in Python 2.7 etree Element has a copy method:
http://hg.python.org/cpython/file/2.7/Lib/xml/etree/ElementTree.py#l233
It is a shallow copy, but that is preferable in some cases.
In my case I am duplicating some SVG Elements and adding a transform. Duplicating children wouldn’t serve any purpose since where relevant they already inherit their parent’s transform.
For future reference.
Simplest way to copy a node (or tree) and keep it’s children, without having to import ANOTHER library ONLY for that:
def copy_tree( tree_root ):
return et.ElementTree( tree_root );
duplicated_node_tree = copy_tree ( node ); # type(duplicated_node_tree) is ElementTree
duplicated_tree_root_element = new_tree.getroot(); # type(duplicated_tree_root_element) is Element
If you procedurally move through your tree with loops, you can use insert
to clone directly ( insert(index, subelement)
) and tree indexing (both in the documentation):
import xml.etree.ElementTree as ET
mytree = ET.parse('some_xml_file.xml') # parse tree from xml file
root = mytree.getroot() # get the tree root
for elem in root: # iterate over children of root
if condition_for_cloning(elem) == True:
elem.insert(len(elem), elem[3]) # insert the 4th child of elem to the end of the element (clone an element)
or for children with some tag:
for elem in root:
children_of_interest = elem.findall("tag_of_element_to_clone")
elem.insert(len(elem), children_of_interest[1])
For anyone visiting from the future:
If you want to clone the entire element, use append
.
new_tree = ET.Element('root')
for elem in a_different_tree:
new_tree.append(elem)
@dennis-williamson made a comment about it which I overlooked and eventually stumbled on the answer here https://stackoverflow.com/a/6533808/4916945