problems with parent.remove(element)
I’m puzzled by a problem to which I found a solution, but I don’t understand it. You can loop through text specifying different elements, as in for tree.iter(tei + ‘w’, tei + ‘pc’): If this: do ‘x’ If that: do ‘y’ But this doesn’t seem to work if the action involved is of the parent.remove(x) kind. In my work I make minor changes in linguistically annotated texts. In the first example below , two <w> elements are moved into one. In the other, a w hi sequence is turned into a single <w>. The result of these and similar operations is a garbage collection problem: there are redundant elements that you want to get rid of: <w lemma="himself" part="I" ">him</w> => <w lemma="himself"> =him selfe</w> <w lemma="himself" part="F" ">selfe</w> => DELETE <w y</w> => <w rendition=”#sup-right,1>ye</w> <hi rend="sup" > => DELETE <w >e</w> </hi> How to do this? Apparently, you can’t do it for each element at the point when it becomes redundant. if w.get(part=”I”): if w.getnext().get(part=”F”): w2 = w.getnext() w.text = w.text + w2.text w.attrib.pop(‘part’) parent= w2.getparent() parent.remove(w2) Code like this works for the first instance, but then stops. I really don’t understand why, but I know it is so. and has something with the behavior of lists. You can ‘pop’ attributes, but you can’t ‘pop’ list items in quite the same way. I’ve used a workaround in which I mark every redundant element with an n=’DELETE’ attribute. Then I loop through the text with a command like for hi in tree.iter(tei + ‘hi’): parent = hi.getparent() parent.remove(hi) This works for a single element. But in my work I generate redundant w, pc, and hi elements for each text. I tried to get rid of those with a command for element in tree.iter(tei + ‘w’, tei +’pc’, tei + ‘hi’): if element.get(‘n’) == ‘DELETE’: parent = element.getparent() parent.remove(element) This does not work. On the other hand, things do work if I iterate through the successively, with just one element for each iteration. That’s not a big deal, though I have 50,000 texts and some of them are very long. Is there a better way of handling this problem from the beginning?
You can loop through text specifying different elements, as in
for tree.iter(tei + ‘w’, tei + ‘pc’): If this: do ‘x’ If that: do ‘y’
But this doesn’t seem to work if the action involved is of the parent.remove(x) kind.
Removals can modify the list of elements iterated on, and the for loop behaviour is not defined in this case. I tend to create a list of deletion candidates, and delete them after the detection loop through the tree. candidates = [] for node in tree.iter(…): if some_criterium(node): candidates.append(node) for node in candidates: node.getparent().remove(node)
Thanks. I had created a list that I called 'garbage' rather than 'candidates', but I thought that the append action would move the element out of where it is. So I didn't run the second part of the cycle. The odd and not particularly intuitive behaviour of list elements in loops is perhaps worth a separate paragraph or subsection both in Stefan's documentation and in John Shipman's excellent tutorial. If I find the time I will draft a section,although a technically more competent person should sign off on it. It might have the title 'Beware of parent.remove' Martin Mueller Professor emeritus of English and Classics Northwestern University On 4/20/17, 16:16, "Jens Quade" <jq@qdevelop.de> wrote:
You can loop through text specifying different elements, as in
for tree.iter(tei + Œw¹, tei + Œpc¹): If this: do Œx¹ If that: do Œy¹
But this doesn¹t seem to work if the action involved is of the parent.remove(x) kind.
Removals can modify the list of elements iterated on, and the for loop behaviour is not defined in this case.
I tend to create a list of deletion candidates, and delete them after the detection loop through the tree.
candidates = []
for node in tree.iter(Š): if some_criterium(node): candidates.append(node)
for node in candidates: node.getparent().remove(node)
participants (2)
-
Jens Quade -
Martin Mueller