使用 zeep (python) 获取 xsd:restriction 的简单类型

Get simpleType with xsd:restriction using zeep (python)

我正在调用 SOAP 服务,我需要在我的请求中传递的元素之一是使用限制枚举值定义的简单类型,如下所示:

<xsd:simpleType name="SAMPLE_SIMPLE_TYPE">
    <xsd:restriction base="xsd:string">
        <xsd:enumeration value="Code"/>
        <xsd:enumeration value="Service_Type_Code"/>
        <xsd:enumeration value="Description"/>
        <xsd:enumeration value="Print_Description"/>
        <xsd:enumeration value="Marketing_Starting_Date"/>
        <xsd:enumeration value="Marketing_Ending_Date"/>
    </xsd:restriction>
</xsd:simpleType>

我通过 zeep 库使用以下语句读取元素

sample_simple_type = client.get_type("ns0:SAMPLE_SIMPLE_TYPE")

但不幸的是,我无法像通常对其他元素那样设置任何值。 (我的意思是我不能设置“代码”、“描述”、“Service_Type_Code”等等)

我似乎需要检索 ns0:SAMPLE_SIMPLE_TYPE 已经有一个枚举值,但我不知道该怎么做。

谢谢

我想你可能想多了。该类型可能是一个限制,但从根本上说它是一个字符串。它不能是任何字符串,只是枚举中的值,但它仍然是一个字符串。所以你可以这样对待它。

这是一个例子。

我在 http://localhost:8080/ 上有一个模拟网络服务 运行ning。它没有做太多,它只是确认请求。模拟服务有这个接口:

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions 
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
xmlns:tns="http://tempuri.org/" 
xmlns:s="http://www.w3.org/2001/XMLSchema" 
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" 
targetNamespace="http://tempuri.org/" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
  <wsdl:types>
    <s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/">
    
    <s:simpleType name="SAMPLE_SIMPLE_TYPE">
        <s:restriction base="s:string">
            <s:enumeration value="Code" />
            <s:enumeration value="Service_Type_Code" />
            <s:enumeration value="Description" />
            <s:enumeration value="Print_Description" />
            <s:enumeration value="Marketing_Starting_Date" />
            <s:enumeration value="Marketing_Ending_Date" />
        </s:restriction>
    </s:simpleType>

    <s:element name="Request">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="1" maxOccurs="1" name="simpleString" type="s:string" />
            <s:element minOccurs="1" maxOccurs="1" name="yourEnumeration" type="tns:SAMPLE_SIMPLE_TYPE" />
          </s:sequence>
        </s:complexType>
    </s:element>
    
    <s:element name="Response">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="1" maxOccurs="1" name="ack" type="s:string" />
          </s:sequence>
        </s:complexType>
      </s:element>
    
    </s:schema>
  </wsdl:types>
  
  <wsdl:message name="TestSoapIn">
    <wsdl:part name="parameters" element="tns:Request" />
  </wsdl:message>
  
  <wsdl:message name="TestSoapOut">
    <wsdl:part name="parameters" element="tns:Response" />
  </wsdl:message>

  <wsdl:portType name="TestSoap">
    <wsdl:operation name="Request">
      <wsdl:input message="tns:TestSoapIn" />
      <wsdl:output message="tns:TestSoapOut" />
    </wsdl:operation>
  </wsdl:portType>

  <wsdl:binding name="TestSoap" type="tns:TestSoap">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="Request">
      <soap:operation soapAction="http://tempuri.org/test" style="document" />
      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  
  <wsdl:binding name="TestSoap12" type="tns:TestSoap">
    <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="Request">
      <soap12:operation soapAction="http://tempuri.org/test" style="document" />
      <wsdl:input>
        <soap12:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  
  <wsdl:service name="Test">
    <wsdl:port name="TestSoap" binding="tns:TestSoap">
      <soap:address location="http://localhost:8080/" />
    </wsdl:port>
    <wsdl:port name="TestSoap12" binding="tns:TestSoap12">
      <soap12:address location="http://localhost:8080/" />
    </wsdl:port>
  </wsdl:service>

</wsdl:definitions>

我已经添加了你的类型。

如果我运行:

python -mzeep http://localhost:8080/test.wsdl

我从 zeep 得到以下方法定义:

...
...
Bindings:
     Soap11Binding: {http://tempuri.org/}TestSoap
     Soap12Binding: {http://tempuri.org/}TestSoap12

Service: Test
     Port: TestSoap (Soap11Binding: {http://tempuri.org/}TestSoap)
         Operations:
            Request(simpleString: xsd:string, yourEnumeration: ns0:SAMPLE_SIMPLE_TYPE) -> ack: xsd:string

     Port: TestSoap12 (Soap12Binding: {http://tempuri.org/}TestSoap12)
         Operations:
            Request(simpleString: xsd:string, yourEnumeration: ns0:SAMPLE_SIMPLE_TYPE) -> ack: xsd:string

现在看到这段代码:

from zeep import Client
from zeep.plugins import HistoryPlugin
from lxml import etree

def print_history(h):
    print(etree.tostring(h.last_sent["envelope"], encoding = "unicode", pretty_print = True))
    print(etree.tostring(h.last_received["envelope"], encoding = "unicode", pretty_print = True))

history = HistoryPlugin()
client = Client('http://localhost:8080/test.wsdl', plugins = [history]) 
    
client.service.Request('whatever', 'Service_Type_Code')
print_history(history)

print('--------------------------------\n')

client.service.Request('whatever', 'bla bla bla')
print_history(history)

print('--------------------------------\n')

sample_simple_type = client.get_type("ns0:SAMPLE_SIMPLE_TYPE")

client.service.Request('whatever', sample_simple_type('Service_Type_Code'))
print_history(history)

print('--------------------------------\n')

client.service.Request('whatever', sample_simple_type('bla bla bla'))
print_history(history)

print('--------------------------------\n')

print(help(sample_simple_type))

它将产生以下输出:

<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
  <soap-env:Body>
    <ns0:Request xmlns:ns0="http://tempuri.org/">
      <ns0:simpleString>whatever</ns0:simpleString>
      <ns0:yourEnumeration>Service_Type_Code</ns0:yourEnumeration>
    </ns0:Request>
  </soap-env:Body>
</soap-env:Envelope>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
   <soapenv:Header/>
   <soapenv:Body>
      <tem:Response>
         <tem:ack>ok</tem:ack>
      </tem:Response>
   </soapenv:Body>
</soapenv:Envelope>

--------------------------------

<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
  <soap-env:Body>
    <ns0:Request xmlns:ns0="http://tempuri.org/">
      <ns0:simpleString>whatever</ns0:simpleString>
      <ns0:yourEnumeration>bla bla bla</ns0:yourEnumeration>
    </ns0:Request>
  </soap-env:Body>
</soap-env:Envelope>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
   <soapenv:Header/>
   <soapenv:Body>
      <tem:Response>
         <tem:ack>ok</tem:ack>
      </tem:Response>
   </soapenv:Body>
</soapenv:Envelope>

--------------------------------

<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
  <soap-env:Body>
    <ns0:Request xmlns:ns0="http://tempuri.org/">
      <ns0:simpleString>whatever</ns0:simpleString>
      <ns0:yourEnumeration>Service_Type_Code</ns0:yourEnumeration>
    </ns0:Request>
  </soap-env:Body>
</soap-env:Envelope>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
   <soapenv:Header/>
   <soapenv:Body>
      <tem:Response>
         <tem:ack>ok</tem:ack>
      </tem:Response>
   </soapenv:Body>
</soapenv:Envelope>

--------------------------------

<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
  <soap-env:Body>
    <ns0:Request xmlns:ns0="http://tempuri.org/">
      <ns0:simpleString>whatever</ns0:simpleString>
      <ns0:yourEnumeration>bla bla bla</ns0:yourEnumeration>
    </ns0:Request>
  </soap-env:Body>
</soap-env:Envelope>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
   <soapenv:Header/>
   <soapenv:Body>
      <tem:Response>
         <tem:ack>ok</tem:ack>
      </tem:Response>
   </soapenv:Body>
</soapenv:Envelope>

--------------------------------

Help on SAMPLE_SIMPLE_TYPE object:

class SAMPLE_SIMPLE_TYPE(zeep.xsd.types.builtins.String)
 |  SAMPLE_SIMPLE_TYPE(qname=None, is_global=False)
 |  
 |  Method resolution order:
 |      SAMPLE_SIMPLE_TYPE
 |      zeep.xsd.types.builtins.String
 |      zeep.xsd.types.builtins.BuiltinType
 |      zeep.xsd.types.simple.AnySimpleType
 |      zeep.xsd.types.any.AnyType
 |      zeep.xsd.types.base.Type
 |      builtins.object
 |  
 |  Methods inherited from zeep.xsd.types.builtins.String:
 |  
 |  pythonvalue(self, value)
 |  
 |  xmlvalue = _wrapper(self, value)
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from zeep.xsd.types.builtins.String:
 |  
 |  accepted_types = [<class 'str'>]
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from zeep.xsd.types.builtins.BuiltinType:
 |  
 |  __init__(self, qname=None, is_global=False)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from zeep.xsd.types.simple.AnySimpleType:
 |  
 |  __call__(self, *args, **kwargs)
 |      Return the xmlvalue for the given value.
 |      
 |      Expects only one argument 'value'.  The args, kwargs handling is done
 |      here manually so that we can return readable error messages instead of
 |      only '__call__ takes x arguments'
 |  
 |  __eq__(self, other)
 |      Return self==value.
 |  
 |  __str__(self)
 |      Return str(self).
 |  
 |  parse_xmlelement(self, xmlelement: lxml.etree._Element, schema: 'Schema' = None, allow_none: bool = True, context: zeep.xsd.context.XmlParserContext = None, schema_type: 'Type' = None) -> Union[str, zeep.xsd.valueobjects.CompoundValue, List[lxml.etree._Element], NoneType]
 |      Try to parse the xml element and return a value for it.
 |      
 |      There is a big chance that we cannot parse this value since it is an
 |      Any. In that case we just return the raw lxml Element nodes.
 |      
 |      :param xmlelement: XML element objects
 |      :param schema: The parent XML schema
 |      :param allow_none: Allow none
 |      :param context: Optional parsing context (for inline schemas)
 |      :param schema_type: The original type (not overriden via xsi:type)
 |  
 |  render(self, node: lxml.etree._Element, value: Union[list, dict, zeep.xsd.valueobjects.CompoundValue], xsd_type: 'ComplexType' = None, render_path=None) -> None
 |  
 |  signature(self, schema=None, standalone=True)
 |  
 |  validate(self, value, required=False)
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from zeep.xsd.types.simple.AnySimpleType:
 |  
 |  __hash__ = None
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from zeep.xsd.types.any.AnyType:
 |  
 |  resolve(self)
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from zeep.xsd.types.base.Type:
 |  
 |  accept(self, value)
 |  
 |  extend(self, child)
 |  
 |  get_prefixed_name(self, schema)
 |  
 |  parse_kwargs(self, kwargs, name, available_kwargs)
 |  
 |  parsexml(self, xml, schema=None)
 |  
 |  restrict(self, child)
 |  
 |  ----------------------------------------------------------------------
 |  Readonly properties inherited from zeep.xsd.types.base.Type:
 |  
 |  attributes
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from zeep.xsd.types.base.Type:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)

None

如您所见,我可以将该参数视为字符串,因为它是一个字符串。从代码中,您可以看到 zeep 甚至不验证值是否来自枚举 (at least for now)。这就是 'bla bla bla' 也有效的原因。

限制是服务器应该强制执行的,因为它是其合同的一部分。如果您发送的不是枚举中的值,您应该返回一个 SoapFault。因为我的服务只是一个愚蠢的模拟,它也没有验证,它只是说它收到了一个请求。