ElementTree and clone element toot

Discussion in 'Python' started by m.banaouas, Feb 2, 2009.

  1. m.banaouas

    m.banaouas Guest

    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.
     
    m.banaouas, Feb 2, 2009
    #1
    1. Advertising

  2. m.banaouas wrote:
    > 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.
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >



    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')
     
    Gerard Flanagan, Feb 2, 2009
    #2
    1. Advertising

  3. En Mon, 02 Feb 2009 12:37:36 -0200, Gerard Flanagan <>
    escribió:

    > 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.

    --
    Gabriel Genellina
     
    Gabriel Genellina, Feb 2, 2009
    #3
  4. Gabriel Genellina wrote:
    > En Mon, 02 Feb 2009 12:37:36 -0200, Gerard Flanagan
    > <> escribió:
    >
    >> 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,


    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?
     
    Gerard Flanagan, Feb 2, 2009
    #4
  5. m.banaouas

    m.banaouas Guest

    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 :
    > En Mon, 02 Feb 2009 12:37:36 -0200, Gerard Flanagan
    > <> escribió:
    >
    >> 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.
    >
     
    m.banaouas, Feb 2, 2009
    #5
  6. En Mon, 02 Feb 2009 14:21:29 -0200, m.banaouas
    <> escribió:

    > 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.

    En Mon, 02 Feb 2009 13:52:59 -0200, Gerard Flanagan <>
    escribió:

    > 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.

    --
    Gabriel Genellina
     
    Gabriel Genellina, Feb 3, 2009
    #6
  7. m.banaouas

    Aahz Guest

    In article <4986bfd7$0$9385$>,
    m.banaouas <> wrote:
    >
    >Working with the ElementTree module, I looked for clone element
    >function but not found such tool:


    Have you tried using copy.deepcopy()?
    --
    Aahz () <*> http://www.pythoncraft.com/

    Weinberg's Second Law: If builders built buildings the way programmers wrote
    programs, then the first woodpecker that came along would destroy civilization.
     
    Aahz, Feb 8, 2009
    #7
  8. Aahz wrote:
    > In article <4986bfd7$0$9385$>,
    > m.banaouas <> wrote:
    >> Working with the ElementTree module, I looked for clone element
    >> function but not found such tool:

    >
    > 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
     
    Stefan Behnel, Feb 9, 2009
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. lordy

    To clone or not to clone..

    lordy, Jul 7, 2006, in forum: Java
    Replies:
    3
    Views:
    741
    lordy
    Jul 7, 2006
  2. andrea valle

    wxPython toot

    andrea valle, Oct 8, 2004, in forum: Python
    Replies:
    0
    Views:
    321
    andrea valle
    Oct 8, 2004
  3. cyberco
    Replies:
    3
    Views:
    522
    Fredrik Lundh
    Nov 19, 2006
  4. Ole Nielsby
    Replies:
    4
    Views:
    430
    Ole Nielsby
    Sep 12, 2007
  5. Kee Nethery
    Replies:
    12
    Views:
    2,165
    Stefan Behnel
    Jun 27, 2009
Loading...

Share This Page