222 lines
6.7 KiB
Python
222 lines
6.7 KiB
Python
"""
|
|
zeep.wsdl.parse
|
|
~~~~~~~~~~~~~~~
|
|
|
|
"""
|
|
from lxml import etree
|
|
|
|
from zeep.exceptions import IncompleteMessage, LookupError, NamespaceError
|
|
from zeep.utils import qname_attr
|
|
from zeep.wsdl import definitions
|
|
|
|
NSMAP = {
|
|
'wsdl': 'http://schemas.xmlsoap.org/wsdl/',
|
|
'wsaw': 'http://www.w3.org/2006/05/addressing/wsdl',
|
|
}
|
|
|
|
|
|
def parse_abstract_message(wsdl, xmlelement):
|
|
"""Create an AbstractMessage object from a xml element.
|
|
|
|
Definition::
|
|
|
|
<definitions .... >
|
|
<message name="nmtoken"> *
|
|
<part name="nmtoken" element="qname"? type="qname"?/> *
|
|
</message>
|
|
</definitions>
|
|
|
|
:param wsdl: The parent definition instance
|
|
:type wsdl: zeep.wsdl.wsdl.Definition
|
|
:param xmlelement: The XML node
|
|
:type xmlelement: lxml.etree._Element
|
|
:rtype: zeep.wsdl.definitions.AbstractMessage
|
|
|
|
"""
|
|
tns = wsdl.target_namespace
|
|
message_name = qname_attr(xmlelement, 'name', tns)
|
|
parts = []
|
|
|
|
for part in xmlelement.findall('wsdl:part', namespaces=NSMAP):
|
|
part_name = part.get('name')
|
|
part_element = qname_attr(part, 'element', tns)
|
|
part_type = qname_attr(part, 'type', tns)
|
|
|
|
try:
|
|
if part_element is not None:
|
|
part_element = wsdl.types.get_element(part_element)
|
|
if part_type is not None:
|
|
part_type = wsdl.types.get_type(part_type)
|
|
|
|
except (NamespaceError, LookupError):
|
|
raise IncompleteMessage((
|
|
"The wsdl:message for %r contains an invalid part (%r): "
|
|
"invalid xsd type or elements"
|
|
) % (message_name.text, part_name))
|
|
|
|
part = definitions.MessagePart(part_element, part_type)
|
|
parts.append((part_name, part))
|
|
|
|
# Create the object, add the parts and return it
|
|
msg = definitions.AbstractMessage(message_name)
|
|
for part_name, part in parts:
|
|
msg.add_part(part_name, part)
|
|
return msg
|
|
|
|
|
|
def parse_abstract_operation(wsdl, xmlelement):
|
|
"""Create an AbstractOperation object from a xml element.
|
|
|
|
This is called from the parse_port_type function since the abstract
|
|
operations are part of the port type element.
|
|
|
|
Definition::
|
|
|
|
<wsdl:operation name="nmtoken">*
|
|
<wsdl:documentation .... /> ?
|
|
<wsdl:input name="nmtoken"? message="qname">?
|
|
<wsdl:documentation .... /> ?
|
|
</wsdl:input>
|
|
<wsdl:output name="nmtoken"? message="qname">?
|
|
<wsdl:documentation .... /> ?
|
|
</wsdl:output>
|
|
<wsdl:fault name="nmtoken" message="qname"> *
|
|
<wsdl:documentation .... /> ?
|
|
</wsdl:fault>
|
|
</wsdl:operation>
|
|
|
|
:param wsdl: The parent definition instance
|
|
:type wsdl: zeep.wsdl.wsdl.Definition
|
|
:param xmlelement: The XML node
|
|
:type xmlelement: lxml.etree._Element
|
|
:rtype: zeep.wsdl.definitions.AbstractOperation
|
|
|
|
"""
|
|
name = xmlelement.get('name')
|
|
kwargs = {
|
|
'fault_messages': {}
|
|
}
|
|
|
|
for msg_node in xmlelement.getchildren():
|
|
tag_name = etree.QName(msg_node.tag).localname
|
|
if tag_name not in ('input', 'output', 'fault'):
|
|
continue
|
|
|
|
param_msg = qname_attr(
|
|
msg_node, 'message', wsdl.target_namespace)
|
|
param_name = msg_node.get('name')
|
|
|
|
try:
|
|
param_value = wsdl.get('messages', param_msg.text)
|
|
except IndexError:
|
|
return
|
|
|
|
if tag_name == 'input':
|
|
kwargs['input_message'] = param_value
|
|
elif tag_name == 'output':
|
|
kwargs['output_message'] = param_value
|
|
else:
|
|
kwargs['fault_messages'][param_name] = param_value
|
|
|
|
wsa_action = msg_node.get(etree.QName(NSMAP['wsaw'], 'Action'))
|
|
param_value.wsa_action = wsa_action
|
|
|
|
kwargs['name'] = name
|
|
kwargs['parameter_order'] = xmlelement.get('parameterOrder')
|
|
return definitions.AbstractOperation(**kwargs)
|
|
|
|
|
|
def parse_port_type(wsdl, xmlelement):
|
|
"""Create a PortType object from a xml element.
|
|
|
|
Definition::
|
|
|
|
<wsdl:definitions .... >
|
|
<wsdl:portType name="nmtoken">
|
|
<wsdl:operation name="nmtoken" .... /> *
|
|
</wsdl:portType>
|
|
</wsdl:definitions>
|
|
|
|
:param wsdl: The parent definition instance
|
|
:type wsdl: zeep.wsdl.wsdl.Definition
|
|
:param xmlelement: The XML node
|
|
:type xmlelement: lxml.etree._Element
|
|
:rtype: zeep.wsdl.definitions.PortType
|
|
|
|
"""
|
|
name = qname_attr(xmlelement, 'name', wsdl.target_namespace)
|
|
operations = {}
|
|
for elm in xmlelement.findall('wsdl:operation', namespaces=NSMAP):
|
|
operation = parse_abstract_operation(wsdl, elm)
|
|
if operation:
|
|
operations[operation.name] = operation
|
|
return definitions.PortType(name, operations)
|
|
|
|
|
|
def parse_port(wsdl, xmlelement):
|
|
"""Create a Port object from a xml element.
|
|
|
|
This is called via the parse_service function since ports are part of the
|
|
service xml elements.
|
|
|
|
Definition::
|
|
|
|
<wsdl:port name="nmtoken" binding="qname"> *
|
|
<wsdl:documentation .... /> ?
|
|
<-- extensibility element -->
|
|
</wsdl:port>
|
|
|
|
:param wsdl: The parent definition instance
|
|
:type wsdl: zeep.wsdl.wsdl.Definition
|
|
:param xmlelement: The XML node
|
|
:type xmlelement: lxml.etree._Element
|
|
:rtype: zeep.wsdl.definitions.Port
|
|
|
|
"""
|
|
name = xmlelement.get('name')
|
|
binding_name = qname_attr(xmlelement, 'binding', wsdl.target_namespace)
|
|
return definitions.Port(name, binding_name=binding_name, xmlelement=xmlelement)
|
|
|
|
|
|
def parse_service(wsdl, xmlelement):
|
|
"""
|
|
|
|
Definition::
|
|
|
|
<wsdl:service name="nmtoken"> *
|
|
<wsdl:documentation .... />?
|
|
<wsdl:port name="nmtoken" binding="qname"> *
|
|
<wsdl:documentation .... /> ?
|
|
<-- extensibility element -->
|
|
</wsdl:port>
|
|
<-- extensibility element -->
|
|
</wsdl:service>
|
|
|
|
Example::
|
|
|
|
<service name="StockQuoteService">
|
|
<documentation>My first service</documentation>
|
|
<port name="StockQuotePort" binding="tns:StockQuoteBinding">
|
|
<soap:address location="http://example.com/stockquote"/>
|
|
</port>
|
|
</service>
|
|
|
|
:param wsdl: The parent definition instance
|
|
:type wsdl: zeep.wsdl.wsdl.Definition
|
|
:param xmlelement: The XML node
|
|
:type xmlelement: lxml.etree._Element
|
|
:rtype: zeep.wsdl.definitions.Service
|
|
|
|
"""
|
|
name = xmlelement.get('name')
|
|
ports = []
|
|
for port_node in xmlelement.findall('wsdl:port', namespaces=NSMAP):
|
|
port = parse_port(wsdl, port_node)
|
|
if port:
|
|
ports.append(port)
|
|
|
|
obj = definitions.Service(name)
|
|
for port in ports:
|
|
obj.add_port(port)
|
|
return obj
|