XML : Subclassing lxml.objectify.ObjectifiedElement

We have some XML documents that use dashes (-) in XML elements which does not play nice with objectified xml elements.

  <rpc-reply xmlns:junos="http://xml.juniper.net/junos/12.3R7/junos">  <route-information xmlns="http://xml.juniper.net/junos/12.3R7/junos-routing">      <route-table>          <table-name>inet.0</table-name>          <destination-count>12</destination-count>          <total-route-count>19</total-route-count>          <active-route-count>12</active-route-count>          <holddown-route-count>0</holddown-route-count>          <hidden-route-count>0</hidden-route-count>      </route-table>  </route-information>  <cli>      <banner>{master}</banner>  </cli>    

So, the obvious happens, and i can access it fine via getattr()

  In [144]: ri = root.getchildren()[0]    In [145]: ri.route-table  ---------------------------------------------------------------------------  AttributeError                            Traceback (most recent call last)  <ipython-input-145-e452e1935e9d> in <module>()  ----> 1 ri.route-table    /opt/brazil-pkg-cache/packages/Lxml/Lxml-3.4.x.13.220/RHEL5_64/DEV.STD.PTHREAD/build/lib/python2.7/site-packages/lxml/objectify.so in lxml.objectify.ObjectifiedElement.__getattr__ (src/lxml/lxml.objectify.c:3494)()    /opt/brazil-pkg-cache/packages/Lxml/Lxml-3.4.x.13.220/RHEL5_64/DEV.STD.PTHREAD/build/lib/python2.7/site-packages/lxml/objectify.so in lxml.objectify._lookupChildOrRaise (src/lxml/lxml.objectify.c:5956)()    AttributeError: no such child: {http://xml.juniper.net/junos/12.3R7/junos-routing}route    In [146]: getattr(ri, 'route-table')  Out[146]: <Element {http://xml.juniper.net/junos/12.3R7/junos-routing}route-table at 0x7f5f9cd5bb48>    

So, I figure this is a nice case to subclass and define my own getattribute that does some converting _ to - on behalf of the user so they can access attributes like ri.route_table.

I also want this to be deal with arbitrary depth and turn this:

  getattr(getattr(ri, 'route-table'), 'total-route-count')    

Into this:

  ri.route_table.total_route_count    

So I need to find a way or sublclassing lxml.objectify.ObjectifiedElement but also make it the value to used to create the objects in the first place

My class would be something basic like (rough idea):

  class ObjectifiedRouteInformation(lxml.objectify.ObjectifiedElement):      """       An adapter class for extracting values from Junos XML RPC replies easier      to use and undertand      """        def __getattribute__(self, attr):          attr = attr.replace('_', '-')          lxml.objectify.ObjectifiedElement.__getattribute__(self, attr)    

Documentation that helped me get to where I am: http://lxml.de/1.3/objectify.html#setting-up-lxml-objectify

Shows how to alter the parser to create objectified elements:

  DEFAULT_PARSER = etree.XMLParser(remove_blank_text=True)  DEFAULT_PARSER.setElementClassLookup(objectify.ObjectifyElementClassLookup())    

Is there any way to inject my new class to make it the default objectified class used to instantiate children.

As all of this is hidden behind c libraries, it's hard to make this determination.

Thanks in advance.

No comments:

Post a Comment