lxml - minor problem appending new element
Peter Otten
__peter__ at web.de
Mon Feb 3 03:39:10 EST 2020
Frank Millman wrote:
> Hi all
>
> I usually send lxml queries to the lxml mailing list, but it appears to
> be not working, so I thought I would try here.
>
> This is a minor issue, and I have found an ugly workaround, but I
> thought I would mention it.
Like this?
children = list(xml)
for y in children:
print(etree.tostring(y))
if y.get('z') == 'c':
child = etree.Element('y', attrib={'z': 'd'})
xml.append(child)
children.append(child)
It doesn't look /that/ ugly to me.
> In Python I can iterate through a list, and on a certain condition
> append a new item to the list, which is then included in the iteration.
Personally I follow the rule "never mutate a list you are iterating over",
even for appends, where the likelihood of problems is small:
items = ["a"]
for item in items:
if item == "a": items.append("a")
> >>> x = ['a', 'b', 'c']
> >>> for y in x:
> ... print(y)
> ... if y == 'b':
> ... x.append('d')
> ...
> a
> b
> c
> d
> >>> x
> ['a', 'b', 'c', 'd']
> >>>
>
> The same thing works in lxml -
>
> >>> lmx = '<x><y z="a"/><y z="b"/><y z="c"/></x>'
> >>> xml = etree.fromstring(lmx)
> >>> for y in xml:
> ... print(etree.tostring(y))
> ... if y.get('z') == 'b':
> ... xml.append(etree.Element('y', attrib={'z': 'd'}))
> ...
> b'<y z="a"/>'
> b'<y z="b"/>'
> b'<y z="c"/>'
> b'<y z="d"/>'
> >>> etree.tostring(xml)
> b'<x><y z="a"/><y z="b"/><y z="c"/><y z="d"/></x>'
>
> However, if it happens that the condition is met on the last item in the
> list, Python still works, but lxml does not include the appended item in
> the iteration. In the following, the only change is checking for 'c'
> instead of 'b'.
>
> >>> x = ['a', 'b', 'c']
> >>> for y in x:
> ... print(y)
> ... if y == 'c':
> ... x.append('d')
> ...
> a
> b
> c
> d
> >>> x
> ['a', 'b', 'c', 'd']
> >>>
>
> >>> lmx = '<x><y z="a"/><y z="b"/><y z="c"/></x>'
> >>> xml = etree.fromstring(lmx)
> >>> for y in xml:
> ... print(etree.tostring(y))
> ... if y.get('z') == 'c':
> ... xml.append(etree.Element('y', attrib={'z': 'd'}))
> ...
> b'<y z="a"/>'
> b'<y z="b"/>'
> b'<y z="c"/>'
> >>> etree.tostring(xml)
> b'<x><y z="a"/><y z="b"/><y z="c"/><y z="d"/></x>'
>
> As you can see, the last element is correctly appended, but is not
> included in the iteration.
>
> Is there any chance that this can be looked at, or is it just the way it
> works?
File a bug report and see if the author is willing to emulate the list
behaviour.
> BTW, I see that ElementTree in the standard library does not have this
> problem.
Maybe uses a list under the hood.
More information about the Python-list
mailing list