Reputation: 22952
How can I remove a processing instruction which is a sibling of the root element in a XML tree?
I can't find any function to do that, and the classic way doesn't work because a head/tail processing instruction has no parent:
from lxml import etree
root = etree.XML("<ROOT/><?foo?>")
tail = root.getnext()
parent = tail.getparent() # parent is None
parent.remove(tail)
I get:
Traceback (most recent call last):
File "/path/to/demo_remove_tail_pi.py", line 6, in <module>
parent.remove(tail)
AttributeError: 'NoneType' object has no attribute 'remove'
Upvotes: 1
Views: 340
Reputation: 7872
This is due the Processing Instructions being generated outside of the root XML tree. This was brought up as a bug many years ago on the LXML's website, but unfortunately it does not look like an appropriate fix was ever implemented.
One of the users on the thread provided a (hackyish) way to remove Processing Instructions that were generated in this manner. Simply take the tag, append it to the root element, and then remove it.
Unlike some other XML libraries, lxml allows an element to occur in one place. That is, you can not copy an element to another place; attempting that moves it to the new location, removing it from the old.
from lxml.etree import XML, tounicode
root = XML("<ROOT/><?foo?>")
print(tounicode(root.getroottree()))
>>> <ROOT/><?foo?>
tail = root.getnext()
root.append(tail)
root.remove(tail)
print(tounicode(root.getroottree()))
>>> <ROOT/>
Upvotes: 1