lxml's element builder and CDATA objects

15 June 2014 (updated 02 May 2016)

Note

Nevermind, this has been fixed in lxml.


lxml has a very nice element builder though it doesn't seem to work with CDATA objects:

>>> from lxml.builder import E
>>> from lxml.etree import CDATA
>>> E.stuff(CDATA('Some stuff that needs to be in a CDATA section'))
Traceback (most recent call last):
  File "<ipython-input-4-40103024e8d8>", line 1, in <module>
    E.stuff(CDATA('Some stuff that needs to be in a CDATA section'))
  File "/usr/lib/python2.7/dist-packages/lxml/builder.py", line 220, in __call__
    raise TypeError("bad argument type: %r" % item)
TypeError: bad argument type: <lxml.etree.CDATA object at 0x238a130>

To fix it, do this:

from lxml.builder import ElementMaker
from lxml.etree import CDATA

def add_cdata(element, cdata):
    assert not element.text, "Can't add a CDATA section. Element already has some text: %r" % element.text
    element.text = cdata

E = ElementMaker(typemap={
    CDATA: add_cdata
})

Then everything works as expected:

>>> from lxml import etree
>>> etree.tostring(E.stuff(CDATA('Some stuff that needs to be in a CDATA section')))
'<stuff><![CDATA[Some stuff that needs to be in a CDATA section]]></stuff>'

This entry was tagged as lxml python