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
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
00158 yielder.switch()
00159
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
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