WSDL 1.1 规范 – Types and Messages 介绍

WSDL 1.1 规范中说到 Types 一般采用成熟的 XSD schema 进行定义, 这样可以保证具有良好的交互性和平台中立性

Message 可以包含 1 个或 n 个 part, part 引用 Types 中定义的数据类型.

在 part 中可以使用如下两个 attribute 对 Types 中的 XSD 进行引用:

  • element.    使用 QName 引用 XSD element
  • type.          使用 QName 引用 XSD simpleType or complexType

为什么 Message 还要由一系列 part 构成呢?这是因为 operation 中的一个输入/输出参数只对一个 Message 进行引用,有些情况下我们需要知道输入/输出参数(其实就是Message)的逻辑结构,比如 RPC binding,而这样的 Message 结构可以充分表

binding 对 portType 中的 operation 和消息格式进行 message 格式和协议详情的定义(与soap进行binding). 一个 portType 可能有数目不定的 binding. binding 语法如下:

<wsdl:binding name=”nmtoken” type=”qname”> *
<soap:binding style=”nmtoken” transport=”nmtoken”/>
<wsdl:operation name=”nmtoken”> *
<soap:operation soapAction=”nmtoken”/>
<wsdl:input name=”nmtoken”? > ?
</wsdl:input>
<wsdl:output name=”nmtoken”? > ?
</wsdl:output>
<wsdl:fault name=”nmtoken”> *
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>

在 binding 中使用 type attribute 引用 portType.

binding 中的 operation 的名字要与该 binding 引用的 portType 中的 operation 的名字保持一致.

注意:由于 operation 的名字不要求唯一,因此这时会有重名情况,这就要求在 portType 定义时对 operation 的名字进行唯一性命名.

binding 必须而且只能指定一个通信协议,比如 http、smtp等
binding 不能指定 WSDL 实现地址信息

TODO: 本例中出现style、transport和soapAction是因为该绑定使用的是SOAP绑定

WSDL 1.1 规范 – portType和operaton介绍

portType 的 operation 支持4种传输原语:

  1. in(One-way) 客户端请求
  2. in-out(Request-response) 客户端请求-服务器端响应
  3. out-in(Solicit-response) 服务器端向客户端发起请求-客户端给服务器端响应
  4. out(Notification) 服务器端通知客户端

尽管 WSDL 规范能够支持这四种 operation,但实际上只定义了前两种。

  • One-way Operation

<wsdl:definitions …. >
<wsdl:portType …. > *
<wsdl:operation name=”nmtoken”>
<wsdl:input name=”nmtoken”? message=”qname”/>
</wsdl:operation>
</wsdl:portType >
</wsdl:definitions>

  • Request-response Operation

<wsdl:portType …. >
<wsdl:operation name=”nmtoken” parameterOrder=”nmtokens”>
<wsdl:input name=”nmtoken”? message=”qname”/>
<wsdl:output name=”nmtoken”? message=”qname”/>
<wsdl:fault name=”nmtoken” message=”qname”/>*
</wsdl:operation>
</wsdl:portType >
(注意:在 xml 中,?表示该项可以出现一次或者根本不出现)

fault 则用于在服务发生异常时,返回给客户端

request-response operation 需要具体的 binding 来说明消息是怎样被发送的:是一次通信(如http request/response)还是两次独立的通信(即两次request/response)

  • Solicit-response Operation

<wsdl:definitions …. >
<wsdl:portType …. > * <!– *表示可以出现0次或多次 –>
<wsdl:operation name=”nmtoken” parameterOrder=”nmtokens”>
<wsdl:output name=”nmtoken”? message=”qname”/>
<wsdl:input name=”nmtoken”? message=”qname”/>
<wsdl:fault name=”nmtoken” message=”qname”/>*
</wsdl:operation>
</wsdl:portType >
</wsdl:definitions>

同样需要具体的 binding 来说明消息是怎样被发送的:是一次通信(如http request/response)还是两次独立的通信(即两次request/response)

  • Notification Operation

<wsdl:definitions …. >
<wsdl:portType …. > * <!– *表示可出现0次或多次 –>
<wsdl:operation name=”nmtoken”>
<wsdl:output name=”nmtoken”? message=”qname”/>
</wsdl:operation>
</wsdl:portType >
</wsdl:definitions>

Operation 的名字

operation 中的 input 或者 output 可以不设置 name,WSLD 将使用默认命名规则:

如果只有 input 或者只有 output,那么这个 input 或者 output 的名称就是它的 operation 的名称;
如果是既有 input 又有 output 或者 既有 output 又有 input,那么input 、output 的名称是 operation 名称加上 Request、Solicit 或者 Response;

fault element 必须自己命名.

Operation 中的参数顺序

Operations 不会说明是否会用于 RPC 样式的 binding. 但是, 如果操作是使用 RPC-binding, 那么(请求的接收方)能够获得原始 RPC 方法签名是非常有用处的. 所以, request-response or solicit-response operation 可以通过 parameterOrder attribute 指定参数名称列表. 在这个列表中, 以一个空白符分隔各 message part 的名字. parameterOrder attribute 必须遵循以下规则:

  1. 各 part 名称的顺序反映了 RPC 方法签名的参数的顺序
  2. 在这个列表中并不指定 return 值
  3. If a part name appears in both the input and output message, it is an in/out parameter
  4. If a part name appears in only the input message, it is an in parameter
  5. If a part name appears in only the output message, it is an out parameter

注意: parameterOrder 属性只是一个建议,并不是强制性的,因此有可能被忽略掉,即使使用 RPC-like binding

另外,本篇的例子中, portType只定义了一个operation, 其实是可以定义多个的, 切不可被误导.

WSDL 1.1 规范 – WSDL范例和各部分介绍

<?xml version="1.0"?>
<definitions name="StockQuote"
      <!-- WSDL的名称 -->
      targetNamespace="http://example.com/stockquote.wsdl"
      <!-- 这个WSDL定义的元素和类型放在这个目标命名空间,
               元素可以指定自己的targetNamespace,
               从而覆盖这个目标命名空间
      -->
      xmlns:tns="http://example.com/stockquote.wsdl"
      <!-- 定义空间前缀,这个命名空间与targetNamespace相同,
               是为了在这个WSDL中引用目标命名空间的元素或者类型,
               即在这个WSDL中定义并放入目标命名空间中的元素或者类型
      -->
      xmlns:xsd1="http://example.com/stockquote.xsd"
      xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
      <!-- SOAP的命名空间,使用SOAP元素时要以这个前缀进行引用 -->
      xmlns="http://schemas.xmlsoap.org/wsdl/">
      <!-- WSDL元素所属的命名空间,如types、message等
               这是一个默认命名空间,即没有空间前缀的都位于这个空间之下
      -->
    <types>
        <!-- 这是使用xml schema定义element,使用了自己的目标命名空间 -->
        <schema targetNamespace="http://example.com/stockquote.xsd"
                  xmlns="http://www.w3.org/2000/10/XMLSchema">
             <element name="TradePriceRequest">
                 <complexType>
                     <all>
                         <element name="tickerSymbol" type="string"/>
                     </all>
                 </complexType>
             </element>
             <element name="TradePrice">
                 <complexType>
                     <all>
                         <element name="price" type="float"/>
                     </all>
                 </complexType>
             </element>
        </schema>
    </types>
    <!-- 定义抽象消息类型 -->
    <message name="GetLastTradePriceInput">
        <part name="body" element="xsd1:TradePriceRequest"/>
            <!-- 使用xsdl前缀引用上面定义的数据类型,
                   xsdl与TradePriceRequest使用的都是同一目标命名空间
                   并且 GetLastTradePriceInput位于
                   targetNamespace="http://example.com/stockquote.wsdl"
                   所以在下面引用这个它时,要使用相同命名空间进行引用,即tns前缀
            -->
    </message>
    <message name="GetLastTradePriceOutput">
        <part name="body" element="xsd1:TradePrice"/>
    </message>
    <!-- 定义接口类型,即这个web服务访问方式
               StockQuotePortType也是在目标命名空间

http://example.com/stockquote.wsdl中

               所以也用tns前缀引用,因为tns也是代表相同命名空间

http://example.com/stockquote.wsdl

    -->
    <portType name="StockQuotePortType">
        <operation name="GetLastTradePrice">
            <input message="tns:GetLastTradePriceInput"/>
            <output message="tns:GetLastTradePriceOutput"/>
        </operation>
    </portType>
    <!--
           portType 的 operation 支持4种传输原语:
           1. in          客户端请求
           2. in-out    客户端请求-服务器端响应
           3. out-in    服务器端向客户端发起请求-客户端给服务器端响应(Solicit)
           4. out        服务器端通知客户端(notification)
           operation 中的 input 或者 output 可以不设置 name,
           如果只有 input 或者只有 output,
           那么这个 input 或者 output 的名称就是它的 operation 的名称;
          如果是既有 input 又有 output 或者 既有 output 又有 input,那么
           input 、output 的名称是 operation 名称加上 Request、Solicit 或者 Response
    -->
    <!-- 将接口类型与soap消息绑定,告知服务调用方式和传输方式 -->
    <binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType">
            <soap:binding style="document"
                transport="http://schemas.xmlsoap.org/soap/http"/>
                <!-- style是传输方式:分rpc和document;transport:分http、smtp等 -->
            <operation name="GetLastTradePrice"><!-- 端口类型声明的operation -->
                <soap:operation soapAction="http://example.com/GetLastTradePrice"/>
                <input>
                    <soap:body use="literal"/>
                </input>
                <output>
                    <soap:body use="literal"/>
                </output>
            </operation>
    </binding>
    <!-- 将接口绑定到具体实现地址 -->
    <service name="StockQuoteService">
            <documentation>My first service</documentation>
            <port name="StockQuotePort" binding="tns:StockQuoteBinding">
                <soap:address location="http://example.com/stockquote"/>
            </port>
    </service>
</definitions>

WSDL 1.1 规范 – WSDL 中的几个 elements

WSDL文档定义了一些服务,这些服务是 endpoint(原文如此。其实就是port,在 WSDL 中改为 endpoint) 或 port 的集合.

在 WSDL 中, endpoint 和 message 的抽象定义独立于它们的具体网络部署(意为:相对于抽象的endpoint,实际情况是怎样的)和数据格式绑定(意为:相对于抽象的 message,它的实际数据格式是怎样的). 这让我们能够重复使用这些抽象定义: messages, 被交换数据的抽象描述, port types, operation 的抽象的集合. 对于一个特定的 port type 来说, 具体的 protocol 和数据格式规范构成了一个可重用的 binding. 一个 port 由网络地址和可重用的 binding 联合定义, 一组 ports 可构成一个 service. 因此, 一个 WSDL 文档使用如下元素定义:

  • Types– 定义数据类型,一般用 XSD(XML Schema Definition)定义.
  • Message– 数据的抽象类型定义(这里的数据是指用来信息交换的数据,用在 SOAP 中).
  • Operation– 服务所支持的操作的抽象描述.
  • Port Type– 一个或多个 endpoint 所支持的一组 operation 的抽象的集合.
  • Binding– 对于一个特定 port type 所使用的具体的 protocol 和数据格式的规范.
  • Port– 由一个 binding 和网络地址联合而定义的一个 endpoint.
  • Service– 相关 endpoint 的一组集合.

除Types外,所有顶级元素可以出现不止1次.