Tu Hoang Tu Hoang - 4 months ago 17
HTML Question

python lxml append element after another element

I have the following HTML markup

<div id="contents">
<div id="content_nav">
something goes here
</div>
<p>
some contents
</p>
</div>


To fix some CSS issue, I want to append a div tag
<div style="clear:both"></div>
after the
content_nav
div like this

<div id="contents">
<div id="content_nav">
something goes here
</div>

<div style="clear:both"></div>

<p>
some contents
</p>
</div>


I am doing it this way:

import lxml.etree

tree = lxml.etree.fromString(inputString, parser=lxml.etree.HTMLParser())

contentnav = tree.find(".//div[@id='content_nav']")
contentnav.append(lxml.etree.XML("<div style='clear: both'></div>"))


But that doesn't append the new
div
right after
content_nav
div but inside.

<div id="content_nav">
something goes here
<div style="clear:both"></div>
</div>


Is there any way to add a
div
in the middle of
content_nav
div and some
p
like that inside
contents
?

Thanks

Answer

Instead of appending to contentnav, go up to the parent (contentdiv) and insert the new div at a particular index. To find that index, use contentdiv.index(contentnav), which gives the index of contentnav within contentdiv. Adding one to that gives the desired index.

import lxml.etree as ET

content='''\
<div id="contents">
    <div id="content_nav">
        something goes here
    </div>
    <p>
        some contents
    </p>   
</div>
'''
tree = ET.fromstring(content, parser=ET.HTMLParser())
contentnav = tree.find(".//div[@id='content_nav']")
contentdiv = contentnav.getparent()
contentdiv.insert(contentdiv.index(contentnav)+1,
                  ET.XML("<div style='clear: both'></div>"))
print(ET.tostring(tree))

yields

<html><body><div id="contents">
    <div id="content_nav">
        something goes here
    </div>
    <div style="clear: both"/><p>
        some contents
    </p>   
</div></body></html>
Comments