2012-04-18 14 views
5

Uso python/suds para implementar un cliente y obtengo prefijos de espacio de nombres incorrectos en el encabezado SOAP enviado para un tipo específico de parámetros definidos por element ref= en el wsdl.python espuma el prefijo de espacio de nombres incorrecto en la solicitud SOAP

El .wsdl hace referencia a un archivo .xsd de tipos de datos, ver a continuación. El problema es con la función GetRecordAttributes y su primer argumento de tipo gbt:recordReferences.

del archivo: browse2.wsdl

<xsd:schema targetNamespace="http://www.grantadesign.com/10/10/Browse" xmlns="http://www.grantadesign.com/10/10/Browse" xmlns:gbt="http://www.grantadesign.com/10/10/GrantaBaseTypes" elementFormDefault="qualified" attributeFormDefault="qualified"> 
<xsd:import schemaLocation="grantabasetypes2.xsd" namespace="http://www.grantadesign.com/10/10/GrantaBaseTypes"/> 
<xsd:element name="GetRecordAttributes"> 
     <xsd:complexType> 
      <xsd:sequence> 
       <xsd:element ref="gbt:recordReferences"> 
       </xsd:element> 

archivo de referencia: grantabasetypes2.xsd

<element name="recordReferences"> 
    <complexType> 
    <sequence> 
     <element name="record" minOccurs="0" maxOccurs="unbounded" type="gbt:MIRecordReference"/> 
    </sequence> 
    </complexType> 
</element> 

solicitud SOAP enviado por espuma:

<SOAP-ENV:Envelope xmlns:ns0="http://www.grantadesign.com/10/10/GrantaBaseTypes" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns2="http://www.grantadesign.com/10/10/Browse" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> 
    <SOAP-ENV:Header/> 
    <ns1:Body> 
     <ns2:GetRecordAttributes> 
     <ns2:recordReferences> 
      <ns0:record> 
      </ns0:record> 
     </ns2:recordReferences> 
     </ns2:GetRecordAttributes> 
    </ns1:Body> 
</SOAP-ENV:Envelope> 

El problema: <ns2:recordReferences> tiene el prefijo incorrecto, debería ser <ns0:recordReferences> ya que pertenece al espacio de nombre ...GrantaBaseTypes definido en .xsd.

Esto ocurre para todos los argumentos definidos por ref= en el wsdl. ¿Cómo se puede arreglar esto automáticamente?

Nota: Comprobé que el prefijo "bueno" es aceptado por el servicio al enviar manualmente la solicitud SOml xml mediante curl.

ACTUALIZACIÓN

me enrede código fuente SUDS y la siguiente las fuerzas fix empíricos todos los elementos con ref= atributo para asumir el espacio de nombres ref-ed (anteriormente, se llevan en el espacio de nombres raíz de esquema o lo que sea tns es) :

del archivo: /suds/xsd/sxbase.py

class SchemaObject(object): 
.... 
    def namespace(self, prefix=None): 

     ns = self.schema.tns 

#FIX BEGIN 
     if self.ref and self.ref in self.schema.elements.keys(): 
      ns = self.ref 
#FIX END 

trabaja con mi servicio, pero no estoy seguro de si se va a romper otra cosa s. Preferiría una solución más inteligente que no cambie el código fuente de SUDS.

Gracias,

Alex

+0

Esto es claramente un error en la pila; ¿A qué te refieres con "automáticamente"? Por ejemplo, ¿está dispuesto a trabajar con un XSD diferente pero equivalente que funcione con sus herramientas? Por lo que dices, si reemplazas la referencia con un elemento definido localmente, funcionará; para todos los cuidados de XSD, el XML generado será el mismo. Si piensas en cambiar en el vuelo, como usar algún tipo de XSLT a través de un proxy, ese sería un enfoque diferente. Podría recomendar una solución que refactorizará automáticamente su XSD para reemplazar refs con elementos locales. –

+0

De hecho, traté de mover y cambiar las definiciones, pero dado que no soy un experto, tal vez no pude precisar la sintaxis correcta, SUDS siguió poniendo el espacio de nombres incorrecto allí. También preferiría no jugar con estos, ya que son proporcionados por un proveedor externo y están sujetos a cambios. Vea ACTUALIZACIÓN para una solución no óptima que encontré hasta ahora. –

Respuesta

8

Escribir un Suds plugin de modificar el código XML antes de ser enviada.

from suds.client import Client 
from suds.plugin import MessagePlugin 

class MyPlugin(MessagePlugin): 
    def marshalled(self, context): 
     #modify this line to reliably find the "recordReferences" element 
     context.envelope[1][0][0].setPrefix('ns0') 

client = Client(WSDL_URL, plugins=[MyPlugin()]) 

Citando la documentación Suds:

movilizados()
proporciona el plugin con la oportunidad de inspeccionar/modificar el documento sobre antes de que se envíe.

+1

Esto funcionará bien para este caso específico. Sin embargo, dado que hay muchos de estos parámetros en varias posiciones de árbol, no es óptimo arreglarlos manualmente. Me gustaría algo como _prefix ns0 para todos los elementos con ref = _, y aunque podría analizarse el árbol xml completo, creo que context.envelope no conserva la información 'ref ='. –

+0

Otra opción es extender 'DocumentPlugin' para modificar el objeto WSDL/XSD, el método' analizado() '(ver los documentos) se llamará dos veces (una para el WSDL, otra para el XSD). – dusan

+0

Brillante, gracias !! Curiosamente, tuve que corregir el sobre en el mismo lugar (estructuralmente) que el ejemplo inicial. ¿Hay un patrón aquí? – Gesias

1

Se puede construir mensaje de jabón sí mismo y utilizar SoapClient para enviar el mensaje:

sc = SoapClient(cli.service.XXXMethod.client,cli.service.XXXMethod.method) 
sc.send(some_soap_doc) 
2

que tenían el mismo problema cuando se utiliza espuma para acceder a un servicio SOAP/IIS BizTalk. Por lo que puedo decir del WSDL ocurre cuando hay un "complexType" que no es parte del "targetNamespace" (tiene su propio), que tiene un elemento secundario que también es un complexType, pero sin espacio de nombres establecido. En BizTalk esto significa que el niño debe pertenecer al mismo espacio de nombres que el padre, pero Suds parece pensar que entonces debería ser parte del targetNamespace ....

La corrección en el código fuente resolvió el problema " correctamente ", pero como quiero poder actualizar sin aplicar la corrección cada vez que busqué otra solución ...

Mi solución fue omitir Suds y copiar el XML sin procesar, usarlo como plantilla y copia los valores en él ... No es hermoso, pero al menos simple. La solución para agregar un complemento es en mi opinión igualmente codificada y quizás aún más difícil de mantener.

0

prefiero expresiones regulares :)

import re 

class EnvelopeFixer(MessagePlugin): 
    def sending(self, context): 
     # rimuovi i prefissi 
     context.envelope = re.sub('ns[0-9]:', '', context.envelope) 
     return context.envelope 
+0

Su método no funciona muy bien: WebFault: error del servidor: 'No se pudo determinar el elemento raíz para la solicitud. – Allen

+0

mmhhh ... así que la estrategia del complemento es la forma ... –

Cuestiones relacionadas