pythonpython-2.7xml-rpcxmlrpclib

How can you adjust xmlrpclib to interpret custom types?


The Python 2.7 xmlrpclib client has the types defined by the XML-RPC standard built-in, plus a few common extensions. Other XML-RPC servers, such as Apache, will however sometimes use their own types, or put extensions in special namespaces, etc.

For example, when you send an 8 byte integer with Apache (which is not covered by the XML-RPC standard), it will send the following response:

<methodResponse xmlns:ex="http://ws.apache.org/xmlrpc/namespaces/extensions">
    <params>
        <param>
            <value>
                <ex:i8>123456789</ex:i8>
            </value>
        </param>
    </params>
</methodResponse>

If you naively try to handle these types with Python you will get an empty tuple result. How can I adjust xmlrpclib to handle such cases?


Solution

  • Internally, xmlrpclib uses the xmlrpclib.Unmarshaller to dispatch responses. The Unmarshaller has a dispatch dictionary in which each type is assigned a function that will handle it.

    Getting the question's example to work is actually quite easy, because xmlrpclib can already handle i8 and we only have to remap ex:i8 to that:

    xmlrpclib.Unmarshaller.dispatch['ex:i8'] = xmlrpclib.Unmarshaller.dispatch['i8']
    

    But for more custom types it might be necessary to write on dispatch functions. Those are designed to be defined within Unmarshaller, so a typical dispatch function looks like this:

    def end_int(self, data):
        self.append(int(data))
        self._value = 0
    dispatch['i8'] = end_int
    

    _value = 0 just indicates that dispatching was successful. So if we had

    <methodResponse>
        <params>
            <param>
                <value>
                    <mycustom>some value</mycustom>
                </value>
            </param>
         </params>
    </methodResponse>
    

    we could define:

    def mycustom_parser(unmarshaller, data):
        unmarshaller.append(data.split())
        unmarshaller._value = 0
    xmlrpclib.Unmarshaller.dispatch['mycustom'] = mycustom_parser