Actually, an Element
is always attached to a ElementTree
even if it looks "detached":
root = etree.XML("<ROOT/>")
assert root.getroottree() is not None
When we use addprevious
/addnext
to insert a processing instruction before/after a root element, the PIs are not attached to a parent element (there isn't any) but they are attached to the root tree instead.
So, the problem lies in the usage of tounicode
(or tostring
). The best practice is to print the XML of the root tree, not the root element.
from lxml import etree
root = etree.XML("<ROOT/>")
root.addprevious(etree.ProcessingInstruction("foo"))
root.addnext(etree.ProcessingInstruction("bar"))
print(etree.tounicode(root))
# => "<ROOT/>"
print(etree.tounicode(root.getroottree()))
# => "<?foo ?><ROOT/><?bar ?>"