Search code examples
pythonsoapspynexmla

python xsd within soap response


I'm using spyne for generating web services in the server side with python to communicate with an excel client (xmla plugin), and I have some difficulties to generate a soap response that match with the client request, what I want is a soap response like this ( under root tag a schema with "xsd:" that refer to xmlns:xsd="http://www.w3.org/2001/XMLSchema in the root :

<soap:Envelope xmlns="urn:schemas-microsoft-com:xml-analysis">
    <soap:Body>
       <DiscoverResponse xmlns="urn:...">
          <return> 
              <root xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                    xmlns="urn:schemas-microsoft-com:xml-analysis:rowset"
                    ....>

                  < xsd:schema targetNamespace="urn:schemas-microsoft-com:xml-analysis:rowset" 


                xmlns:sql="urn:schemas-microsoft-com:xml-sql">
                <xsd:element name="root">
                <xsd:complexType>
                <xsd:sequence minOccurs="0" maxOccurs="unbounded">
                <xsd:element name="row" type="row"/>
                </xsd:sequence>
                </xsd:complexType>
                </xsd:element>
                <xsd:simpleType name="uuid">
                <xsd:restriction base="xsd:string">
                <xsd:pattern value="[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}"/>
                </xsd:restriction>
                </xsd:simpleType>
                <xsd:complexType name="xmlDocument">
                <xsd:sequence>
                <xsd:any/>
                </xsd:sequence>
                </xsd:complexType>
                <xsd:complexType name="row">
                <xsd:sequence>
                <xsd:element sql:field="PropertyName" name="PropertyName" type="xsd:string"/>
                <xsd:element sql:field="PropertyDescription" name="PropertyDescription" type="xsd:string" minOccurs="0"/>
                <xsd:element sql:field="PropertyType" name="PropertyType" type="xsd:string" minOccurs="0"/>
                <xsd:element sql:field="PropertyAccessType" name="PropertyAccessType" type="xsd:string"/>
                <xsd:element sql:field="IsRequired" name="IsRequired" type="xsd:boolean" minOccurs="0"/>
                <xsd:element sql:field="Value" name="Value" type="xsd:string" minOccurs="0"/>
                </xsd:sequence>
                </xsd:complexType>
                </xsd:schema>

            </root>
        </return>
    </DiscoverResponse>
</soap:Body>

the result that i got with spyne every time doesn't contains the xsd: :

  <soap11env:Body>
<tns:DiscoverResponse>
  <tns:return>
    <ns2:root xmlns:ns2="urn:schemas-microsoft-com:xml-analysis:rowset">
      <ns3:schema xmlns:ns3="services.models" targetNamespace="urn:schemas-microsoft-com:xml-analysis:rowset"/>
    </ns2:root>
  </tns:return>
</tns:DiscoverResponse>

here is my python code :
in models.py file:

class schema(ComplexModel):
targetNamespace = XmlAttribute(Unicode)
__type_name__ = "schema"

class DiscoverResponse(ComplexModel):
__namespace__ = "urn:schemas-microsoft-com:xml-analysis:rowset"
root = Array(schema.customize(max_occurs='unbounded'))

in xmla.py file :

class xmla_provider(ServiceBase):

    @rpc(Unicode,
     Restrictionlist,
     Propertielist,
     _returns=[DiscoverResponse],
     _out_variable_names=["return"])

        def Discover(ctx, RequestType, Restrictions, Properties):
            response = DiscoverResponse()
            response.root = schema(targetNamespace="urn:schemas-microsoft-com:xml-analysis:rowset"),
            return response

to resolve the problem I tried to add __ namespace __ = "http://www.w3.org/2001/XMLSchema" in class schema and i got this problem
if child_ns != ns and not child_ns in self.imports[ns] and \ KeyError: 'http://www.w3.org/2001/XMLSchema'

another solution that comes to mind and which is not a good solution, is to force a soap response by returning all

<xsd:schema targetNamespace="urn:schemas-microsoft-com:xml-analysis:rowset" 
            xmlns:sql="urn:schemas-microsoft-com:xml-sql">....  

to root attribut as Unicode
here is the code: in xmla.py

  response.root = "\n  < xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns='urn:schemas-microsoft-com:xml-analysis:rowset' ....

in model.py

class DiscoverResponse(ComplexModel):
__namespace__ = "urn:schemas-microsoft-com:xml-analysis:rowset"
root = Unicode

and I got this output

DEBUG:spyne.protocol.xml:Response <soap11env:Envelope xmlns:soap11env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="urn:schemas-microsoft-com:xml-analysis">
 <soap11env:Body>
<tns:DiscoverResponse>
  <tns:return>
    <ns0:root xmlns:ns0="urn:schemas-microsoft-com:xml-analysis:rowset">

      &lt; xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'
      xmlns='urn:schemas-microsoft-com:xml-analysis:rowset'
      xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
      xmlns:sql='urn:schemas-microsoft-com:xml-sql' 

      ....

      /xsd:schema

  </ns0:root>
  </tns:return>
</tns:DiscoverResponse>

all < > characters are replaced by "& lt;" and "& gt;" (as I said this is not a good solution, normally I have to solve the problem with name spaces )

please any suggestion to solve the problem or in the worst case, any suggestion of soap library in python that allow this kind of response


Solution

  • You need to switch to bare mode and return AnyXml like this:

    class DiscoverRequest(ComplexModel):
        RequestType = Unicode
        Restrictions = Restrictionlist
        Properties = Propertielist
    
    
    class HelloWorldService(ServiceBase):
        @rpc(DiscoverRequest, _returns=AnyXml, _body_style="bare")
        def Discover(ctx, request):
            return etree.fromstring("""<root>whatever</root>""")