ElementTree and clone element toot

M

m.banaouas

Hi all,
Working with the ElementTree module, I looked for clone element function but not
found such tool:

def CloneElment(fromElem, destRoot = None)
fromElem is the element to clone
destRoot is the parent element of the new element ; if None so the new element
will be child of fromElem parent. The clone operation is recursive to make it
process all subtree of the element to clone.

here is my first implementation:

def CloneElement(fromElem, destRoot = None):
if destRoot == None:
fromRoot = ET.ElementTree(fromElem).getroot()
destRoot = fromRoot
destElem = destRoot.makeelement(fromElem.tag, fromElem.attrib)
destRoot.append(destElem)
destElem.text = fromElem.text
for e in fromElem.findall('*'):
CloneElement(e, destElem)
#
this function works fine only if destRoot parameter is defined by the caller
context. The problem is about retreiving parent element: I didn't found any way
to determine the parent element of an element "elem" by asking elem itself!
and ET.ElementTree(fromElem).getroot() is wrong because it returns fromElem
itself, not its parent.

Thanks for any help.
 
G

Gerard Flanagan

m.banaouas said:
Hi all,
Working with the ElementTree module, I looked for clone element function but not
found such tool:

def CloneElment(fromElem, destRoot = None)
fromElem is the element to clone
destRoot is the parent element of the new element ; if None so the new element
will be child of fromElem parent. The clone operation is recursive to make it
process all subtree of the element to clone.

here is my first implementation:

def CloneElement(fromElem, destRoot = None):
if destRoot == None:
fromRoot = ET.ElementTree(fromElem).getroot()
destRoot = fromRoot
destElem = destRoot.makeelement(fromElem.tag, fromElem.attrib)
destRoot.append(destElem)
destElem.text = fromElem.text
for e in fromElem.findall('*'):
CloneElement(e, destElem)
#
this function works fine only if destRoot parameter is defined by the caller
context. The problem is about retreiving parent element: I didn't found any way
to determine the parent element of an element "elem" by asking elem itself!
and ET.ElementTree(fromElem).getroot() is wrong because it returns fromElem
itself, not its parent.

Thanks for any help.


Maybe `dest = ET.fromstring(ET.tostring(src))` would do?

Or as follows:

from xml.etree import ElementTree as ET

s = '''
<root>
<a name="A">text
<b name="B"><bb name="BB">BBtext
</bb></b>
</a>
<c />
<d name="D" />
<e>EEText</e>
</root>
'''

e = ET.fromstring(s)

def clone(elem):
ret = elem.makeelement(elem.tag, elem.attrib)
ret.text = elem.text
for child in elem:
ret.append(clone(child))
return ret

f = clone(e)

assert ''.join(ET.tostring(e).split()) == ''.join(ET.tostring(f).split())

assert f[0].get('name') == e[0].get('name')

f[0].set('name', 'NEWNAME')

assert f[0].get('name') == 'NEWNAME'
assert f[0].get('name') != e[0].get('name')
 
G

Gabriel Genellina

e = ET.fromstring(s)

def clone(elem):
ret = elem.makeelement(elem.tag, elem.attrib)
ret.text = elem.text
for child in elem:
ret.append(clone(child))
return ret

f = clone(e)

You forget the tail attribute, and you also should use the SubElement
factory instead of makeelement as documented; doing that fixes the
"parent" issue too.
 
G

Gerard Flanagan

Gabriel said:
En Mon, 02 Feb 2009 12:37:36 -0200, Gerard Flanagan


You forget the tail attribute,

I did, thanks.

and you also should use the SubElement
factory instead of makeelement as documented; doing that fixes the
"parent" issue too.

I suppose I would have just used the Element factory if the OP hadn't
otherwise:

def clone(elem):
ret = ET.Element(elem.tag, elem.attrib)
ret.text = elem.text
ret.tail = elem.tail
for child in elem:
ret.append(clone(child))
return ret

Not sure what SubElement gains you, in the context of the above function?
 
M

m.banaouas

My python version is 2.4.4

def SubElement(parent, tag, attrib={}, **extra):

Can you tell me how does "parent" issue could be solved by SubElement ?
I'm looking for how to determine element parent just by asking element it self.
It seems like element doesn't know witch is its parent, while any parent knows
well witch are its childs.

My goal is to clone an element and attach it to a specified parent or to parant
of original element to clone.

may be better implementation of CloneElement is to let the caller context make
the attachement between the clone and its parent.

Gabriel Genellina a écrit :
 
G

Gabriel Genellina

En Mon, 02 Feb 2009 14:21:29 -0200, m.banaouas
My python version is 2.4.4

def SubElement(parent, tag, attrib={}, **extra):

Can you tell me how does "parent" issue could be solved by SubElement ?

Simply because you *have* to pass a parent to the function...
I'm looking for how to determine element parent just by asking element
it self.

There isn't a way -- and there are good reasons. One is memory management
(it would create reference cycles, and they aren't efficiently removed).
Another one is that it prevents an element to be shared between containers.
My goal is to clone an element and attach it to a specified parent or to
parant of original element to clone.

Then pass the desired parent as the "parent" argument.

Not sure what SubElement gains you, in the context of the above function?

Just because Element and SubElement are documented as the recommended way
to create Element instances. Also, I was under the impression that
makeelement did not make a copy of its "attrib" argument, so it would end
being shared by other instances too -- but it isn't the case actually.
 
S

Stefan Behnel

Aahz said:
Have you tried using copy.deepcopy()?

While being the most obvious solution, calling deepcopy() on an Element is
surprisingly slow in ElementTree.

http://codespeak.net/lxml/performance.html#deepcopy

It's actually multiple times faster to rebuild the tree manually through
the API than to let deepcopy() do it. Fredrik also has written a little
factory for mass reproduction of Element trees.

http://effbot.python-hosting.com/file/stuff/sandbox/elementlib/clone.py

Stefan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top