https://effbot.org/zone/element-xmlrpc.htm
==========
Uso de ElementTrees para generar mensajes XML-RPC
11 de julio de 2002 | Fredrik Lundh
Este es un trabajo en progreso.El protocolo XML-RPC proporciona una manera simple de llamar a servicios remotos a través de una red. El protocolo se basa en estándares conocidos y ampliamente utilizados como HTTP y XML, y simplemente agrega una forma estándar de formatear solicitudes y paquetes de respuesta, y convertir valores de parámetros a XML y viceversa.
Para llamar a un servicio remoto, cree un documento XML que describa su solicitud de acuerdo con las instrucciones en la especificación XML-RPC, y use HTTP para publicarlo en el servidor. Si todo va bien, el servidor devolverá un documento XML que contiene la respuesta.
Aquí hay un ejemplo simple de solicitud (directamente de la especificación XML-RPC):
<? xml version = "1.0"?> <methodCall> <methodName> examples.getStateName </methodName> <params> <param> <value><i4>41</i4> </value> </param> </ params> </methodCall>
La solicitud consta de un elemento methodCall de nivel superior , que contiene dos subelementos, methodName y params .
Como su nombre lo indica, el elemento methodName contiene el nombre del procedimiento remoto a invocar. En este caso, el nombre es examples.getStateName , que se puede interpretar como un método getStateName proporcionado por el servicio de ejemplos .
El elemento params , finalmente, contiene parámetros para pasar al procedimiento. Debe contener varios subelementos param , cada uno con un valor . El elemento params es opcional; Si el procedimiento no toma argumentos, puede omitirlo.
El siguiente script utiliza el módulo httplib para enviar esta solicitud a un servidor userland.com:
host = "betty.userland.com"
handler = "/ RPC2"
body = "" "\
<? xml version =" 1.0 "?>
<methodCall>
<methodName> examples.getStateName </methodName>
<params>
<param>
<value><i4>41</i4> </value>
</param>
</params>
</methodCall>
"" " def do_request (host, controlador, cuerpo): desde httplib import HTTP # send xml-rpc request h = HTTP (host) h.putrequest ( "POST", controlador) h.putheader ( "User-Agent", "element-xmlrpc") h.putheader ( "Host", host) h.putheader ( "Content-Type", "text / xml") h.putheader (
"Content-Length", str (len (body))) h.endheaders () h.send (body) # busca la respuesta errcode, errmsg, headers = h.getreply () if errcode! = 200: raise Exception (errcode , errmsg) return h.getfile () print do_request (host, handler, body) .read ()
Suponiendo que betty.userland.com está en funcionamiento, el script anterior produce el siguiente resultado (o algo muy similar):
<? xml version = "1.0"?> <methodResponse> <params> <param> <value> South Dakota </value> </param> </params> </methodResponse>
La respuesta es similar en estructura. El elemento toplevel nos dice que este es methodResponse , y los valores de retorno se almacenan en un elemento params .
Analizando la respuesta
En lugar de imprimir la respuesta, podemos analizarla en un ElementTree y usar métodos de elementos estándar para acceder al contenido de la respuesta:
file = do_request (host, handler, body) import ElementTree tree = ElementTree.parse (file) methodResponse = tree.getroot () for param in methodResponse.find ( "params"): print repr (param [0] .text)
Si ejecuta este script, imprimirá 'Dakota del Sur' (a menos que alguien haya movido las cosas, por supuesto).
Parámetros de codificación y valores de retorno
Ambos parámetros y valores de retorno siempre se almacenan en elementos de valor , utilizando un subelemento para especificar tanto el tipo (en el campo de etiqueta) como el valor (como texto). Para las cadenas, puede omitir el subelemento y almacenar el valor de la cadena en el propio elemento de valor.
XML-RPC admite los siguientes elementos de tipo:
- i4 o int
-
Un entero con signo de 32 bits.
- booleano
-
Un valor booleano, o marca: 0 para falso, 1 para verdadero.
- cuerda
-
Una cadena de caracteres XML (consulte también XML-RPC y la limitación ASCII ).
- doble
-
Un número de coma flotante con signo de doble precisión (64 bits).
- dateTime.iso8601
-
Fecha / hora dada como una cadena ISO 8601 de 17 caracteres: "aaaammddThh: mm: dd". Tenga en cuenta que el valor se da como un "tiempo ingenuo"; No incluye una zona horaria.
- base64
-
Datos binarios, almacenados como texto codificado en base64
- formación
-
Una colección ordenada de valores (similar a una lista de Python). El elemento de matriz debe tener un subelemento denominado datos , que puede contener cualquier cantidad de subelementos de valor . Las matrices se pueden anidar.
- estructura
-
Una colección desordenada de pares cadena / valor (similar a un diccionario de Python). El elemento struct puede contener cualquier número de subelementos miembros , cada uno con un elemento de nombre con la cadena de clave y un elemento de valor que contiene el valor. Las estructuras se pueden anidar.
Continuará…
Notas:
El módulo http_xml contiene código para enviar y recibir árboles de elementos a través de HTTP.
El siguiente fragmento de código decodifica un argumento de valor, de forma recursiva:
desde base64 import decodestring
unmarshallers = { "int": lambda x: int (x.text), "i4": lambda x: int (x.text), "boolean": lambda x: bool (int (x.text) ), "string": lambda x: x.text o "", "double": lambda x: float (x.text), "dateTime.iso8601": lambda x: datetime (x.text), "array": lambda x: [unmarshal (v) para v en x [0]], "struct": lambda x: dict ([(k.text o "", unmarshal (v)) para k, v en x]), " base64 ": lambda x:decodestring (x.text o "")} def
unmarshal (elem): if elem: value = elem [0] return unmarshallers [value.tag] (value) return elem.text o ""
Aquí hay una versión alternativa de la línea de estructura, que también funciona en Python 2.1:
"struct": lambda x: ([d para d en [{}]], [d.setdefault (k.text o "", unmarshal (v)) para (k, v) en x], d) [2 ],
Hmm Tal vez debería comenzar con una versión un poco más legible, utilizando funciones separadas de arreglo de matriz y estructura de arreglo ...
Aquí hay un fragmento que crea una solicitud XML-RPC, con parámetros dados como una secuencia:
def marshal_method_call (method_name, params):
method_call_elem = Element ( "methodCall")
SubElement (method_call_elem, "methodName"). text = method_name si params: params_elem = SubElement (method_call_elem, "params") para obtener el valor en params: Elem = Subm params_elem, "param") elem.append (marshal (value)) return method_call_elem
Y aquí hay un fragmento que crea una respuesta XML-RPC. Tenga en cuenta que un método solo puede devolver un valor único; para devolver múltiples valores, colóquelos en una tupla.
def marshal_method_response (params):
method_response_elem = Element ( "methodResponse")
param_elem = SubElement (
SubElement (method_response_elem, "params"), "param" ) param_elem.append (marshal (params)) return method_response_elem
Aquí hay una versión trozo de mariscal. Esta versión solo admite algunos tipos de datos:
marshallers = {
type (0): lambda x, v: (SubElement (x, "i4"), str (v)),
type (0.0): lambda x, v: (SubElement (x, "double"), str (v)), escriba ( ""): lambda x, v: (SubElement (x, "string"), v)} def marshal (value): value_elem = Element ( "value") elem, elem.text = marshallers [type (value)] (value_elem, value) return value_elem