[lxml-dev] Custom elements, class lookup and xpath

Hi! I am playing around with custom element classes, and encountered the following problem: when using xpath to find a specific (custom) element, the element that is returned is not an instance of the custom element class. Instead, it is an instance of the standard Element class. This causes any call to a method of the custom class to fail with an AttributeError. See (simplified but working) code below. I have just started using lxml, so I am not very experienced; however, I could not find an answer to my question in the online tutorial and reference material, while google did not give any clues either. Can anyone help me with this? Is the class lookup method implemented correctly in my code? It seems to work when the custom elements are generated... Thanks! Roel ### Start of code ### from lxml import etree as ET class BliepElement(ET.ElementBase): TAG = 'bliep' def test(self): print "Bliep is testing!" class BlupElement(ET.ElementBase): TAG = 'blup' def test(self): print "Blup is testing!" def addBliep(self): x = self.xpath('//bliep') if not x: b = BliepElement() self.insert(0, b) def getBliep(self): x = self.xpath('//bliep') if not x: return None else: return x[0] class MyLookup(ET.CustomElementClassLookup): def lookup(self, nodetype, document, namespace, name): if name=='bliep': return BliepElement if name=='blup': return BlubElement parser = ET.XMLParser() parser.set_element_class_lookup(MyLookup()) ET.Element = parser.makeelement b1 = BlupElement() b1.addBliep() b2 = b1.getBliep() print ET.tostring(b1) print type(b1).mro() print type(b2).mro(b2.test() ### End of code ### Output when run in terminal: $ python test.py <blub><bliep/></blub> [<class '__main__.BlupElement'>, <type 'lxml.etree.ElementBase'>, <type 'lxml.etree._Element'>, <type 'object'>] [<type 'lxml.etree._Element'>, <type 'object'>] Traceback (most recent call last): File "test.py", line 54, in <module> b2.test() AttributeError: 'lxml.etree._Element' object has no attribute 'test'

Hi, Roel Zinkstok wrote:
parser = ET.XMLParser() parser.set_element_class_lookup(MyLookup()) ET.Element = parser.makeelement
This doesn't do what (I guess) you expect. The Element() factory is a pure API functions and is not used internally.
b1 = BlupElement() b1.addBliep() b2 = b1.getBliep()
You should read the warning here: http://codespeak.net/lxml/element_classes.html#generating-xml-with-custom-cl... However, it seems the way to handle this isn't documented on the doc pages, only on the ElementBase class. You can add a PARSER attribute to the custom Element classes, whose configuration will then be used for Element class lookups. Stefan

You can add a PARSER attribute to the custom Element classes, whose configuration will then be used for Element class lookups.
Thanks a lot, indeed adding a PARSER=parser statement to the custom element classes (combined with removing the ET.Element = parser.makeelement statement) did solve the issue. Roel
participants (2)
-
Roel Zinkstok
-
Stefan Behnel