xml_rpc.py

Go to the documentation of this file.
00001 """\
00002 @file xml_rpc.py
00003 @brief An implementation of a parser/generator for the XML-RPC xml format.
00004 
00005 $LicenseInfo:firstyear=2006&license=mit$
00006 
00007 Copyright (c) 2006-2008, Linden Research, Inc.
00008 
00009 Permission is hereby granted, free of charge, to any person obtaining a copy
00010 of this software and associated documentation files (the "Software"), to deal
00011 in the Software without restriction, including without limitation the rights
00012 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00013 copies of the Software, and to permit persons to whom the Software is
00014 furnished to do so, subject to the following conditions:
00015 
00016 The above copyright notice and this permission notice shall be included in
00017 all copies or substantial portions of the Software.
00018 
00019 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00020 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00021 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00022 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00023 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00024 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00025 THE SOFTWARE.
00026 $/LicenseInfo$
00027 """
00028 
00029 
00030 from greenlet import greenlet
00031 
00032 from mulib import mu
00033 
00034 from xml.sax import handler
00035 from xml.sax import parseString
00036 
00037 
00038 # States
00039 class Expected(object):
00040     def __init__(self, tag):
00041         self.tag = tag
00042 
00043     def __getattr__(self, name):
00044         return type(self)(name)
00045 
00046     def __repr__(self):
00047         return '%s(%r)' % (
00048             type(self).__name__, self.tag)
00049 
00050 
00051 class START(Expected):
00052     pass
00053 
00054 
00055 class END(Expected):
00056     pass
00057 
00058 
00059 class STR(object):
00060     tag = ''
00061 
00062 
00063 START = START('')
00064 END = END('')
00065 
00066 
00067 class Malformed(Exception):
00068     pass
00069 
00070 
00071 class XMLParser(handler.ContentHandler):
00072     def __init__(self, state_machine, next_states):
00073         handler.ContentHandler.__init__(self)
00074         self.state_machine = state_machine
00075         if not isinstance(next_states, tuple):
00076             next_states = (next_states, )
00077         self.next_states = next_states
00078         self._character_buffer = ''
00079 
00080     def assertState(self, state, name, *rest):
00081         if not isinstance(self.next_states, tuple):
00082             self.next_states = (self.next_states, )
00083         for next in self.next_states:
00084             if type(state) == type(next):
00085                 if next.tag and next.tag != name:
00086                     raise Malformed(
00087                         "Expected %s, got %s %s %s" % (
00088                             next, state, name, rest))
00089                 break
00090         else:
00091             raise Malformed(
00092                 "Expected %s, got %s %s %s" % (
00093                     self.next_states, state, name, rest))
00094 
00095     def startElement(self, name, attrs):
00096         self.assertState(START, name.lower(), attrs)
00097         self.next_states = self.state_machine.switch(START, (name.lower(), dict(attrs)))
00098 
00099     def endElement(self, name):
00100         if self._character_buffer.strip():
00101             characters = self._character_buffer.strip()
00102             self._character_buffer = ''
00103             self.assertState(STR, characters)
00104             self.next_states = self.state_machine.switch(characters)
00105         self.assertState(END, name.lower())
00106         self.next_states = self.state_machine.switch(END, name.lower())
00107 
00108     def error(self, exc):
00109         self.bozo = 1
00110         self.exc = exc
00111 
00112     def fatalError(self, exc):
00113         self.error(exc)
00114         raise exc
00115 
00116     def characters(self, characters):
00117         self._character_buffer += characters
00118 
00119 
00120 def parse(what):
00121     child = greenlet(xml_rpc)
00122     me = greenlet.getcurrent()
00123     startup_states = child.switch(me)
00124     parser = XMLParser(child, startup_states)
00125     try:
00126         parseString(what, parser)
00127     except Malformed:
00128         print what
00129         raise
00130     return child.switch()
00131 
00132 
00133 def xml_rpc(yielder):
00134     yielder.switch(START.methodcall)
00135     yielder.switch(START.methodname)
00136     methodName = yielder.switch(STR)
00137     yielder.switch(END.methodname)
00138 
00139     yielder.switch(START.params)
00140 
00141     root = None
00142     params = []
00143     while True:
00144         state, _ = yielder.switch(START.param, END.params)
00145         if state == END:
00146             break
00147 
00148         yielder.switch(START.value)
00149         
00150         params.append(
00151             handle(yielder))
00152 
00153         yielder.switch(END.value)
00154         yielder.switch(END.param)
00155 
00156     yielder.switch(END.methodcall)
00157     ## Resume parse
00158     yielder.switch()
00159     ## Return result to parse
00160     return methodName.strip(), params
00161 
00162 
00163 def handle(yielder):
00164     _, (tag, attrs) = yielder.switch(START)
00165     if tag in ['int', 'i4']:
00166         result = int(yielder.switch(STR))
00167     elif tag == 'boolean':
00168         result = bool(int(yielder.switch(STR)))
00169     elif tag == 'string':
00170         result = yielder.switch(STR)
00171     elif tag == 'double':
00172         result = float(yielder.switch(STR))
00173     elif tag == 'datetime.iso8601':
00174         result = yielder.switch(STR)
00175     elif tag == 'base64':
00176         result = base64.b64decode(yielder.switch(STR))
00177     elif tag == 'struct':
00178         result = {}
00179         while True:
00180             state, _ = yielder.switch(START.member, END.struct)
00181             if state == END:
00182                 break
00183 
00184             yielder.switch(START.name)
00185             key = yielder.switch(STR)
00186             yielder.switch(END.name)
00187 
00188             yielder.switch(START.value)
00189             result[key] = handle(yielder)
00190             yielder.switch(END.value)
00191 
00192             yielder.switch(END.member)
00193         ## We already handled </struct> above, don't want to handle it below
00194         return result
00195     elif tag == 'array':
00196         result = []
00197         yielder.switch(START.data)
00198         while True:
00199             state, _ = yielder.switch(START.value, END.data)
00200             if state == END:
00201                 break
00202 
00203             result.append(handle(yielder))
00204 
00205             yielder.switch(END.value)
00206 
00207     yielder.switch(getattr(END, tag))
00208 
00209     return result
00210 
00211 
00212 VALUE = mu.tag_factory('value')
00213 BOOLEAN = mu.tag_factory('boolean')
00214 INT = mu.tag_factory('int')
00215 STRUCT = mu.tag_factory('struct')
00216 MEMBER = mu.tag_factory('member')
00217 NAME = mu.tag_factory('name')
00218 ARRAY = mu.tag_factory('array')
00219 DATA = mu.tag_factory('data')
00220 STRING = mu.tag_factory('string')
00221 DOUBLE = mu.tag_factory('double')
00222 METHODRESPONSE = mu.tag_factory('methodResponse')
00223 PARAMS = mu.tag_factory('params')
00224 PARAM = mu.tag_factory('param')
00225 
00226 mu.inline_elements['string'] = True
00227 mu.inline_elements['boolean'] = True
00228 mu.inline_elements['name'] = True
00229 
00230 
00231 def _generate(something):
00232     if isinstance(something, dict):
00233         result = STRUCT()
00234         for key, value in something.items():
00235             result[
00236                 MEMBER[
00237                     NAME[key], _generate(value)]]
00238         return VALUE[result]
00239     elif isinstance(something, list):
00240         result = DATA()
00241         for item in something:
00242             result[_generate(item)]
00243         return VALUE[ARRAY[[result]]]
00244     elif isinstance(something, basestring):
00245         return VALUE[STRING[something]]
00246     elif isinstance(something, bool):
00247         if something:
00248             return VALUE[BOOLEAN['1']]
00249         return VALUE[BOOLEAN['0']]
00250     elif isinstance(something, int):
00251         return VALUE[INT[something]]
00252     elif isinstance(something, float):
00253         return VALUE[DOUBLE[something]]
00254 
00255 def generate(*args):
00256     params = PARAMS()
00257     for arg in args:
00258         params[PARAM[_generate(arg)]]
00259     return METHODRESPONSE[params]
00260 
00261 
00262 if __name__ == '__main__':
00263     print parse("""<?xml version="1.0"?> <methodCall>  <methodName>examples.getStateName</methodName>  <params>  <param>  <value><i4>41</i4></value>  </param>  </params>  </methodCall>
00264 """)
00265     
00266         
00267         
00268         
00269         
00270         
00271         
00272         
00273         

Generated on Fri May 16 08:31:53 2008 for SecondLife by  doxygen 1.5.5