    # This requires the free xml-rpc library available from
    # http://www.pythonware.com/products/xmlrpc/
    #
    # See Examples/XMLRPCExample.py for sample usage.
    #

    # Sometimes xmlrpclib is installed as a package, sometimes not.  So we'll
    # make sure it works either way.
    try:
        from xmlrpclib import xmlrpclib
    except ImportError:
        import xmlrpclib
    import sys, string, traceback
    from RPCServlet import RPCServlet

    class XMLRPCServlet(RPCServlet):
        """
        XMLRPCServlet is a base class for XML-RPC servlets.
        See Examples/XMLRPCExample.py for sample usage.

        For more Pythonic convenience at the cost of language independence,
        see PickleRPCServlet.
        """
        def respondToPost(self, transaction):
            """
            This is similar to the xmlrpcserver.py example from the xmlrpc
            library distribution, only it's been adapted to work within a
            WebKit servlet.
            """
            try:
                # get arguments
                data = transaction.request().rawInput(rewind=1).read()
                encoding = _getXmlDeclAttr(data, "encoding")
                params, method = xmlrpclib.loads(data)

                # generate response
                try:
                    # This first test helps us to support PythonWin, which uses
                    # repeated calls to __methods__.__getitem__ to determine the
                    # allowed methods of an object.
                    if method == '__methods__.__getitem__':
                        response = self.exposedMethods()[params[0]]
                    else:
                        response = self.call(method, *params)
                    if type(response) != type(()):
                        response = (response,)
                except Exception, e:
                    fault = self.resultForException(e, transaction)
                    response = xmlrpclib.dumps(xmlrpclib.Fault(1, fault), encoding=encoding)
                    self.sendOK('text/xml', response, transaction)
                    self.handleException(transaction)
                except:  # if it's a string exception, this gets triggered
                    fault = self.resultForException(sys.exc_info()[0], transaction)
                    response = xmlrpclib.dumps(xmlrpclib.Fault(1, fault), encoding=encoding)
                    self.sendOK('text/xml', response, transaction)
                    self.handleException(transaction)
                else:
                    response = xmlrpclib.dumps(response, methodresponse=1, encoding=encoding)
                    self.sendOK('text/xml', response, transaction)
            except:
                # internal error, report as HTTP server error
                print 'XMLRPCServlet internal error'
                print string.join(traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2]))
                transaction.response().setStatus(500, 'Server Error')
                self.handleException(transaction)

    # Helper functions

    def _getXmlDeclAttr(xml, attName):
        """ gets attribute value from xml declaration (<?xml ... ?>) """
        s = xml[6 : xml.find("?>")] # 'version = "1.0" encoding = "Cp1251"'
        p = s.find(attName)
        if p==-1:
            return None
        s=s[p+len(attName):]        # '= "Cp1251"'
        s=s[s.find('=')+1:].strip() # '"Cp1251"'
        return s[1:s.find(s[0],1)]  # 'Cp1251'