作者(按姓氏字母顺序排列):
Erik Christensen,Microsoft
Francisco Curbera,IBM
Greg Meredith,Microsoft
Sanjiva Weerawarana,IBM
版权所有© 2000 Ariba,International Business Machines Corporation,Microsoft
WSDL 是一种 XML 格式,用于将网络服务描述为一组端点,这些端点对包含面向文档信息或面向过程信息的消息进行操作。这种格式首先对操作和消息进行抽象描述,然后将其绑定到具体的网络协议和消息格式上以定义端点。相关的具体端点即组合成为抽象端点(服务)。可以对 WSDL 进行扩展,这样无论通信时使用何种消息格式或网络协议,都可以对端点及其消息进行描述。但是,本文档中所述的绑定只涉及有关如何将 WSDL 与 SOAP 1.1、HTTP GET/POST 和 MIME 一起使用的问题。
此版本的 WSDL 语言尚处于初步阶段,没有提供框架来说明端点的撰写过程。描述这些约定的完整框架应包含撰写服务的方式和表达服务行为的方式(即相应的用于发送和接收消息的规则)。服务的撰写应满足两个要求:(1) 确保类型的安全性,(2) 允许在运行时通过交换和绑定服务引用来传递引用。后面的这一条对于在运行期协商约定以及捕获引用服务和代理服务的行为至关重要。
WSDL 规范的作者希望及时发布 WSDL 的修订版和/或一些附加文档,包括:(1) 撰写服务的框架;(2) 描述服务行为的框架。
本草案介绍了 Ariba、IBM 和 Microsoft 当前在服务描述方面的一些思路。它对 NASSL、SCL 和 SDL(有关这方面的早期建议)中的一些概念进行了整理合并。
由于通信协议和消息格式在 Web 社区中已经过标准化,因而有可能以某种结构化的方式对通信加以描述,而且实现这一点也显得日益重要。WSDL 定义了一种 XML 语法,将网络服务描述为能够进行消息交换的通信端点的集合,从而满足了这种需求。WSDL 服务定义为分布式系统提供了文档,并且可用于自动执行应用程序通信中所涉及的细节。
WSDL 文档将服务定义为网络端点或端口的集合。在 WSDL 中,由于端点和消息的抽象定义已从具体的网络部署或数据格式绑定中分离出来,因此可以对抽象定义进行再次使用:消息,指对交换数据的抽象描述;而端口类型,指操作的抽象集合。用于特定端口类型的具体协议和数据格式规范构成了可以再次使用的绑定。将网络地址与可再次使用的绑定相关联,可以定义一个端口,而端口的集合则定义为服务。因此,WSDL 文档在网络服务的定义中使用下列元素:
- Types - 数据类型定义的容器,它使用某种类型系统(如 XSD)。
- Message - 通信数据的抽象类型化定义。
- Operation - 对服务所支持的操作的抽象描述。
- Port Type - 操作的抽象集合,这些操作由一个或多个端点支持。
- Binding - 特定端口类型的具体协议和数据格式规范。
- Port - 定义为绑定和网络地址组合的单个端点。
- Service - 相关端点的集合。
将在第二节中对这些元素进行详细说明。应该注意的是,WSDL 并没有引入新的类型定义语言。虽然 WSDL 知道,要描述消息格式需要丰富的类型系统,并且它也支持“XML 架构规范 (XSD)”作为其标准类型系统,但是,由于不可能只用一种类型系统语法来描述现在和将来的所有消息格式,因此 WSDL 允许通过扩展来使用其它类型定义语言。
此外,WSDL 还定义了通用的绑定机制。通过该机制可使特定的协议、数据格式或结构与抽象的消息、操作或端点相关联。该机制还允许对抽象定义进行再次使用。
虽然本文档定义了上述语言扩展,但这些扩展均位于核心服务定义框架的上部。所以一定能将 WSDL 与其它绑定扩展一起使用。
下例是一个提供股票报价的简单服务的 WSDL 定义。该服务支持名为 GetLastTradePrice 的单一操作,这个操作是通过在 HTTP 上运行 SOAP 1.1 协议来实现的。该请求接受一个类型为字符串的 ticker 符号,并返回类型为浮点数的价格。有关此定义中所用元素的详细说明,请参见第 2 节(核心语言)和第 3 节(SOAP 绑定)。
示例 1 通过 HTTP 运行的 SOAP 1.1 请求/响应
<?xml version="1.0"?> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote.wsdl" xmlns:tns="http://example.com/stockquote.wsdl" xmlns:xsd1="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <types> <schema targetNamespace="http://example.com/stockquote.xsd" xmlns="http://www.w3.org/1999/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:TradePrice"/> </message> <message name="GetLastTradePriceOutput"> <part name="body" element="xsd1:TradePriceResult"/> </message> <portType name="StockQuotePortType"> <operation name="GetLastTradePrice"> <input message="tns:GetLastTradePriceInput"/> <output message="tns:GetLastTradePriceOutput"/> </operation> </portType> <binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="GetLastTradePrice"> <soap:operation soapAction="http://example.com/GetLastTradePrice"/> <input> <soap:body use="literal" namespace="http://example.com/stockquote.xsd" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output> <soap:body use="literal" namespace="http://example.com/stockquote.xsd" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation> </binding> <service name="StockQuoteService"> <documentation>我的第一次服务</documentation> <port name="StockQuotePort" binding="tns:StockQuoteBinding"> <soap:address location="http://example.com/stockquote"/> </port> </service> </definitions>
1. 本文档中的关键字“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY”和“OPTIONAL”按照 RFC-2119中的说明进行解释。
2. 本文档中使用下列名称空间前缀:
前缀 | 名称空间 URI | 定义 |
wsdl | http://schemas.xmlsoap.org/wsdl/ | WSDL 框架的 WSDL 名称空间。 |
http | http://schemas.xmlsoap.org/wsdl/http/ | HTTP GET 和 POST 绑定的 WSDL 名称空间。 |
mime | http://schemas.xmlsoap.org/wsdl/mime/ | MIME 绑定的 WSDL 名称空间。 |
xsi | http://www.w3.org/1999/XMLSchema-instance | 由 XSD 定义的实例名称空间。 |
xsd | http://www.w3.org/1999/XMLSchema | 由 XSD 定义的架构名称空间。 |
tns | (多种) | “this namespace”(tns) 是用于指当前文档的惯用前缀。 |
(other) | (多种) | 其它名称空间前缀仅作为示例。其中,以“http://example.com”开头的 URI 代表某些与应用程序相关或与上下文相关的 URI |
3. 此规范使用非正式语法来描述 WSDL 文档的 XML 语法:
- 语法以 XML 实例的形式出现,但是值表示数据类型,而非实际值。
- 应按如下方式将字符追加到元素和属性后:“?”(0 或 1);“*”(0 或更多);“+”(1 或更多)。
- 以“…”结尾的元素名称(如 <element…/> 或 <element…>)表示省略与上下文无关的元素/属性。
- 上文中尚未正式引入以粗体显示的语法,或仅在某个特定示例中出现。
- <-- extensibility element --> 是某些“other”名称空间(如 XSD 中的 ##other)中的元素占位符。
- 以上定义的 XML 名称空间前缀用于表示所定义的元素的名称空间。
- 以 <?xml 开头的示例中包含足够的信息,可以满足本规范的要求,而其它示例则只是一些片段,需要指定其它信息才能满足本规范的要求。
XSD 架构是作为 WSDL 语法的正式定义提供的:
本节介绍 WSDL 语言的核心元素。有关 SOAP、HTTP 和 MIME 绑定扩展的信息,请分别参见第 3 节、第 4 节和第 5 节。
WSDL 文档实际上只是一个定义集。在根部有一个 definitions 元素,其中包含一些定义。具体语法如下所示:
<wsdl:definitions name="nmtoken"? targetNamespace="uri"?> <import namespace="uri" location="uri"/>* <wsdl:documentation…/> ? <wsdl:types> ? <wsdl:documentation…/>? <xsd:schema…/>* <-- extensibility element --> * </wsdl:types> <wsdl:message name="nmtoken> * <wsdl:documentation…/>? <part name="nmtoken" element="qname"? type="qname"?/> * </wsdl:message> <wsdl:portType name="nmtoken">* <wsdl:documentation…/>? <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> </wsdl:portType> <wsdl:binding name="nmtoken" type="qname">* <wsdl:documentation…/>? <-- extensibility element --> * <wsdl:operation name="nmtoken">* <wsdl:documentation…/> ? <-- extensibility element --> * <wsdl:input name="nmtoken"?> ? <wsdl:documentation…/> ? <-- extensibility element --> </wsdl:input> <wsdl:output name="nmtoken"?> ? <wsdl:documentation…/> ? <-- extensibility element --> * </wsdl:output> <wsdl:fault name="nmtoken"> * <wsdl:documentation…/> ? <-- extensibility element --> * </wsdl:fault> </wsdl:operation> </wsdl:binding> <wsdl:service name="nmtoken"> * <wsdl:documentation…/>? <wsdl:port name="nmtoken" binding="qname"> * <wsdl:documentation…/> ? <-- extensibility element --> </wsdl:port> <-- extensibility element --> </wsdl:service> <-- extensibility element --> * </wsdl:definitions>
服务是使用以下五个主要元素来定义的:
- types:提供用于描述所交换消息的数据类型定义。
- message:代表所传输数据的抽象定义。消息由一些逻辑片段构成,每个逻辑片段分别与某个类型系统中的定义相关联。
- portType:指抽象操作的集合。每个操作引用一条输入消息和一条输出消息。
- binding:为由特定 portType 定义的操作和消息指定具体的协议和数据格式规范。
- port:为绑定指定一个地址,从而定义一个通信端点。
- service:用于聚合一组相关端口。
将在第 2.2 至 2.7 节中对这些元素进行详细说明。本节的其余部分将介绍 WSDL 中有关文档命名、引用文档定义、使用语言扩展和添加上下文文档等方面的规则。
文档命名和链接
可以为 WSDL 文档分配一个类型为 NCNAME 的可选 name 属性(该属性将作为文档的一种轻量级形式)。或者,也可以指定一个类型为 URI 的 targetNamespace 属性。该 URI 不能是相对 URI。
WSDL 允许使用 import 语句将名称空间与文档位置相关联:
<definitions…> <import namespace="uri" location="uri"/> * </definitions>
WSDL 中的 QNames 解析方法与 XML 架构规范中所述的 QNames 解析方法相似。
使用 QName 可以创建对 WSDL 定义的引用。可以引用 WSDL 文档中的以下各类定义:
- WSDL 定义:service、port、message、bindings 和 portType
- 其它定义:如果通过扩展添加了其它定义,这些定义应使用 QName 链接。
上面列出的每种 WSDL 定义类型都有自己的名称范围(也就是说,端口名称和消息名称绝对不会发生冲突)。同一个名称范围内的名称在 WSDL 文档中必须是唯一的。
撰写样式
<?xml version="1.0"?> <schema targetNamespace="http://example.com/stockquote/schemas" xmlns="http://www.w3.org/1999/XMLSchema"> <element name="GetLastTradePrice"> <complexType> <all> <element name="tickerSymbol" type="string"/> </all> </complexType> </element> <element name="GetLastTradePriceResult"> <complexType> <all> <element name="result" type="float"/> </all> </complexType> </element> </schema>
http://example.com/stockquote/stockquote.wsdl
<?xml version="1.0"?> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote/definitions" xmlns:tns="http://example.com/stockquote/definitions" xmlns:xsd1="http://example.com/stockquote/schemas" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <import namespace="http://example.com/stockquote/schemas" location="http://example.com/stockquote/stockquote.xsd"/> <message name="GetLastTradePriceRequest"> <part name="body"element="xsd1:GetLastTradePrice"/> </message> <message name="GetLastTradePriceResponse"> <part name="body"element="xsd1:GetLastTradePriceResult"/> </message> <portType name="StockQuotePortType"> <operation name="GetLastTradePrice"> <input message="tns:GetLastTradePriceRequest"/> <output message="tns:GetLastTradePriceResponse"/> </operation> </portType> </definitions>
http://example.com/stockquote/stockquoteservice.wsdl
<?xml version="1.0"?> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote/service" xmlns:tns="http://example.com/stockquote/service" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <import namespace="http://example.com/stockquote/definitions" location="http://example.com/stockquote/stockquote.wsdl"/> <binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType"> <soap:binding style="document"/> <operation name="GetLastTradePrice"> <soap:operation soapAction="http://my.org/GetLastTradePrice"/> </operation>> </binding> <service name="StockQuoteService"> <documentation>我的第一个服务</documentation> <port name="StockQuotePort" binding="tns:StockQuoteBinding"> <soap:address location="http://my.org/stockquote"/> </port> </service> </definitions>
语言的扩展性和绑定
在 WSDL 中,术语“绑定”表示将协议或数据格式信息与某个抽象实体(如 message、operation 或 portType 等)相关联的过程。WSDL 允许将代表特定技术的元素(此处称为扩展性元素)放置在 WSDL 所定义的各种元素之下。这些可扩展点通常用于指定特定协议或消息格式的绑定信息,但也可用于其它用途。扩展性元素所用的 XML 名称空间不能与 WSDL 的名称空间相同。附录 A3 中详细说明了扩展性元素可在文档中的哪些位置出现。
扩展性元素通常用于指定某种特定技术的绑定。为了区分特定技术绑定的语义对通信是必需的还是可选的,可以在扩展性元素上设置一个布尔型的 wsdl:required 属性。该属性的默认值为假 (false)。定义该属性的名称空间为“
有关扩展性元素的示例,请参见第 3 节、第 4 节和第 5 节。
文档
WSDL 使用可选的 wsdl:document 元素作为可阅读文档的容器。该元素的内容可以是任意文本和元素(混杂在 XSD 中)。在所有 WSDL 语言元素中,都允许使用文档元素。
types 元素包含与交换的消息相关的数据类型定义。为了获得最大程度的互操作性和平台中立性,WSDL 选用 XSD 作为标准类型系统,并将其当作固有类型系统。
<definitions…> <types> <xsd:schema…/>* </types> </definitions>
可以使用 XSD 类型系统来定义消息中的类型,无论所得到的线上格式是否为 XML,也无论所得到的 XSD 架构是否验证了该特定线上格式。如果同一消息具有多个绑定,或者虽然只有一个绑定,但该绑定类型的类型系统不通用,则会出现非常有趣的情况。在这种情况下,如果使用 XSD 对抽象类型进行编码,建议遵循下列原则:
- 使用元素形式(不要使用属性)。
- 不要使用对线上编码非常特殊的属性或元素(也就是说,与消息的抽象内容无关的属性或元素),例如,soap:root、soap:encodingStyle、xmi:id 和 xmi:name 等。
- 使用 Soap:Array 类型来为数组类型建模(无论最终形式是否实际使用 SOAP 1.1 版文档的第 5 节中指定的编码方式)。使用 ArrayOfXXX 作为数组类型的名称(其中,XXX 表示数组中项的类型)。
但是,由于不可能使用一种类型系统语法来描述现在和将来的所有抽象类型,因此,WSDL 允许通过扩展性元素来添加类型系统。扩展性元素可能出现在 types 元素之下,它标识正在使用的类型定义系统并为类型定义提供 XML 容器元素。该元素的作用与 XML 架构语言的 schema 元素的作用相似。
<definitions…> <types> <-- type-system extensibility element --> * </types> </definitions>
消息由一个或多个逻辑片段构成。每个片段使用一个消息类型属性与某个类型系统的类型相关联。消息类型属性的集合是可扩展的。WSDL 定义了以下几个消息类型属性,与 XSD 一起使用:
- element:使用 QName 引用一个 XSD 元素。
- type:使用 QName 引用一个 XSD simpleType 或 complexType。
如果使用的名称空间与 WSDL 所用的名称空间不同,还可以定义其它消息类型属性。绑定扩展性元素也可以使用消息类型属性。
定义消息的语法如下所示。其中,消息类型属性以粗体显示(消息类型属性因所用类型系统而异)。
<definitions…> <message name="nmtoken"> * <part name="nmtoken"? element="qname" type="qname"?/> * </message> </definitions>
消息 name 属性所指定的名称在其所在 WSDL 文档定义的全部消息中是唯一的。
片段 name 属性所指定的名称在其所在消息的所有片段中是唯一的。
消息片段
片段是一种用于描述消息的逻辑抽象内容的灵活机制。绑定可以引用片段的名称来指定有关该片段的绑定专用信息。例如,如果定义用于 RPC 的消息,片段可以代表消息中的参数。但是,为了确定该片段的实际含义,必须对绑定进行检查。
如果消息有多个逻辑单元,则使用多个片段元素。例如,以下消息包括“订单”和“客户”两个片段元素。
<definitions…> <types> <schema…> <element name="PO" type="tns:POType"/> <complexType name="POType"> <element name="id" type="string/> <element name="name" type="string"/> <element name="items"> <complexType> <element name="item" type="tns:Item" minOccurs="0" maxOccurs="unbounded"/> </complexType> </element> </complexType> <complexType name="Item"> <element name="quantity" type="int"/> <element name="product" type="string"/> </complexType> <element name="Customer" type="tns:CustomerType"/> <complexType name="CustomerType"> <element name="name" type="string"/> </complexType> </schema> </types> <message name="PO"> <part name="po" element="tns:PO"/> <part name="customer" element="tns:Customer"/> </message> </definitions>
但是,如果消息内容十分复杂,则需要使用另一种语法,通过直接使用类型系统来指定消息的复合结构。在下例中,主体是一个订单或一组客户。
<definitions…> <types> <schema…> <complexType name="POType"> <element name="id" type="string/> <element name="name" type="string"/> <element name="items"> <complexType> <element name="item" type="tns:Item" minOccurs="0" maxOccurs="unbounded"/> </complexType> </element> </complexType> <complexType name="Item"> <element name="quantity" type="int"/> <element name="product" type="string"/> </complexType> <complexType name="CustomerType"> <element name="name" type="string"/> </complexType> <complexType name="Composite"> <choice> <element name="PO" minOccurs="1" maxOccurs="1" type="tns:POType"/> <element name="Customer" minOccurs="0" maxOccurs="unbounded" type="tns:CustomerType"/> </choice> </complexType> </schema> </types> <message name="PO"> <part name="composite" type="tns:Composite"/> </message> </definitions>
抽象消息与具体消息
消息定义始终被当作消息内容的抽象定义。消息绑定描述如何将抽象内容映射为具体的格式。但是,在某些情况下,抽象定义可能与一个或多个绑定的具体表示方式完全相符或十分接近,致使这些绑定不能提供任何映射信息或只能提供少量信息;而同一消息定义的另一个绑定可能需要大量的映射信息。因此,只有在对绑定进行检查之后,才能确定消息的实际“抽象程度”。
端口类型是一组指定的抽象操作,以及所涉及的抽象消息。
<wsdl:definitions…> <wsdl:portType name="nmtoken"> <wsdl:operation name="nmtoken"…/> * </wsdl:portType> </wsdl:definitions>
端口类型 name 属性所指定的名称在其所在 WSDL 文档定义的所有端口类型中是唯一的。
操作是通过 name 属性来命名的。
WSDL 提供以下四个可得到端点支持的传输原语:
- 单向 (One-way):端点接收消息。
- 请求响应 (Request-response):端点接收消息,然后发送相关消息。
- 要求响应 (Solicit-response):端点发送消息,然后接收相关消息。
- 通知 (Notification):端点发送消息。
WSDL 称这些原语为操作。虽然可以使用两条单向消息抽象地模拟请求/响应或要求/响应,但是将其作为原语操作类型模型也很有用,因为:
- 经常需要使用这两个操作。
- 可以使顺序相互关联,而不必引入更为复杂的流信息。
- 某些端点可以只接收消息(如果它们是同步请求响应的结果)。
- 需要流定义时,可以通过算法从这些原语派生简单的流。
虽然请求/响应或要求/响应在 WSDL 文档中是逻辑相关的,仍然有一个特定的绑定描述具体的相关信息。例如,请求消息和响应消息可以作为一两个实际网络通信的一部分进行交换。
操作使用类型为 QName 的 message 属性来引用所涉及的消息。该属性遵循 WSDL 为链接定义的规则。
单向操作
单向操作的语法是:
<wsdl:definitions…> <wsdl:portType…> * <wsdl:operation name="nmtoken"> <wsdl:input name="nmtoken"? message="qname"/> </wsdl:operation> </wsdl:portType > </wsdl:definitions>
input 元素指定单向操作的抽象消息格式。
请求响应操作
请求响应操作的语法是:
<wsdl:definitions…> <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 > </wsdl:definitions>
input 元素和 output 元素分别指定请求和响应的抽象消息格式。可选的 fault 元素为操作可能产生的错误消息(协议所特有的除外)指定抽象消息格式。
请注意,请求响应操作是一个抽象的概念;必须查询特定的绑定,才能确定消息的实际发送方式:是在同一个通信中发送(例如 HTTP 请求/响应),还是作为两个独立的通信发送(例如两个 HTTP 请求)。
要求响应操作
<wsdl:definitions…> <wsdl:portType…> * <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>
output 元素和 input 元素分别指定所要求的请求和响应的抽象消息格式。可选的 fault 元素为操作可能产生的错误消息(协议所特有的除外)指定抽象消息格式。
请注意,请求响应操作是一个抽象的概念;必须查询特定的绑定,才能确定消息的实际发送方式:是在同一个通信中发送(例如 HTTP 请求/响应),还是作为两个独立的通信发送(例如两个 HTTP 请求)。
通知操作
单向操作的语法是:
<wsdl:definitions…> <wsdl:portType…> * <wsdl:operation name="nmtoken"> <wsdl:output name="nmtoken"? message="qname"/> </wsdl:operation> </wsdl:portType > </wsdl:definitions>
output元素指定通知操作的抽象消息格式。
操作中的元素名称
inuput 元素和 output 元素的 name 属性所指定的名称在其所在端口类型的所有 input 元素和 output 元素中是唯一的。
为了避免需要为操作中的每个 input 元素和 output 元素指定名称,WSDL 提供了一些以操作名称为基础的默认值。如果未在单向消息或通知消息中指定 name 属性,则该属性默认为操作的名称;如果未在请求响应或要求响应操作的输入或输出消息中指定 name 属性,则该属性默认为分别附带有“Request”/“Solicit”或“Response”的操作名称。
必须为每个 fault 元素指定名称,绑定才能指定错误消息的具体格式。fault 元素的名称在为该操作定义的错误集合中是唯一的。
操作中的参数顺序
操作并不指定它们是否与类似 RPC 这样的绑定一起使用。但是,当操作与 RPC 绑定一起使用时,能够捕获原始 RPC 函数签名非常有用。因此,请求响应或要求响应操作可以通过类型为 nmtokens 的 parameterOrder 属性来指定参数名称列表。该属性的值是一个由单个空格分隔的消息片段名称列表。指定的片段必须遵循以下规则:
- 指定片段的顺序必须反映 RPC 签名中的参数顺序
- return 值片段不在列表中出现
- 如果片段名称同时在输入和输出消息中出现,则片段是 in/out 参数
- 如果片段名称只在输入消息中出现,则片段是 in 参数
- 如果片段名称只在输出消息中出现,则片段是 out 参数
请注意,该信息仅作为“提示”,对于那些不关心 RPC 签名的用户,完全可以忽略。而且,即使当操作与类似 RPC 这样的绑定一起使用时,也不是必须使用该信息。
绑定为特定 portType 所定义的操作和消息指定消息格式和协议细节。对于某个给定的 portType,可能有多个绑定。绑定的语法如下所示:
<wsdl:definitions…> <wsdl:binding name="nmtoken" type="qname"> * <-- extensibility element (1) --> * <wsdl:operation name="nmtoken"> * <-- extensibility element (2) --> * <wsdl:input name="nmtoken"?> ? <-- extensibility element (3) --> </wsdl:input> <wsdl:output name="nmtoken"?> ? <-- extensibility element (4) --> * </wsdl:output> <wsdl:fault name="nmtoken"> * <-- extensibility element (5) --> * </wsdl:fault> </wsdl:operation> </wsdl:binding> </wsdl:definitions>
name 属性所指定的名称在其所在 WSDL 文档定义的所有绑定中是唯一的。
绑定使用 type 属性引用它所绑定的 portType。QName 值遵循由 WSDL 定义的链接规则。
绑定的 operation、input、output 和 fault 元素使用各自的 name 属性与相应的 portType 元素相互关联,其行为就象在 portType 中一样。
通过绑定扩展性元素可指定输入消息 (3)、输出消息 (4) 和错误消息 (5) 的具体语法。还可以指定每个操作的绑定信息 (2) 和每个绑定的信息 (1)。
绑定必须明确指定一个协议。
绑定不能指定地址信息。
端口通过为绑定指定一个地址来定义一个端点。
<wsdl:definitions…> <wsdl:service…> * <wsdl:port name="nmtoken" binding="qname"> * <-- extensibility element (1) --> </wsdl:port> </wsdl:service> </wsdl:definitions>
name 属性所指定的名称在其所在 WSDL 文档定义的所有端口中是唯一的。
binding 属性(类型为 QName)使用 WSDL 所定义的链接规则引用绑定。
绑定扩展性元素 (1) 用于指定端口的地址信息。
一个端口不能指定多个地址。
端口不能指定除地址信息之外的任何绑定信息。
服务将一组相关端口组合在一起:
<wsdl:definitions…> <wsdl:service name="nmtoken"> * <wsdl:port…/>* </wsdl:service> </wsdl:definitions>
name 属性所指定的名称在其所在 WSDL 文档定义的所有服务中是唯一的。
服务中的端口具有如下关系:
- 所有端口都不相互通信(也就是说,一个端口的输出不会是另一个端口的输入)。
- 如果一个服务中有几个端口属于同一端口类型,但是使用了不同的绑定或地址,则这些端口是可以互相替换的端口。每个端口根据每个绑定所规定的传输限制和消息格式限制提供在语义上等价的行为。这就使得 WSDL 文档的使用者可以根据某些标准(如协议、距离等)来选择要与之通信的特定端口。
- 通过检查端口,我们可以确定服务的端口类型,从而使 WSDL 文档的使用者可以根据所支持的端口类型来确定是否要与特定的服务通信。在端口类型的操作之间存在某种隐含关系时,这非常有用,而且只有存在完整的端口类型集合时才能完成某个特定的任务。
WSDL 包含用于 SOAP 1.1 端点的绑定,该绑定支持指定以下协议专用信息:
- 指示某个绑定已绑定到 SOAP 1.1 协议
- 指定 SOAP 端点地址的方法
- SOAPAction HTTP 标头的 URI(该标头用于 SOAP 的 HTTP 绑定)
- 标头定义列表,这些标头作为 SOAP 信包的一部分进行传输
- 在 XSD 中指定 SOAP 根的方法
此绑定语法并不完整,这是因为 SOAP 的绑定集在不断扩展。您完全可以从此语法的某些部分派生出其它 SOAP 绑定。例如:
- 不使用 URI 寻址架构的 SOAP 绑定可以替换另一个寻址架构,方法是 soap:address 元素。
- 不需要 SOAPAction 的 SOAP 绑定可以省略soapAction 属性。
在下例中,将把一个 SubscribeToQuotes SOAP 1.1 单向消息通过 SMTP 绑定发送到 StockQuote 服务。该请求接受类型为字符串的 ticker 符号,并包含一个定义订阅 URI 的标头。
示例 3. 使用 SOAP 标头在 SMTP 之上运行的单向操作的 SOAP 绑定
<?xml version="1.0"?> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote.wsdl" xmlns:tns="http://example.com/stockquote.wsdl" xmlns:xsd1="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <message name="SubscribeToQuotes"> <part name="body" element="xsd1:SubscribeToQuotes"/> </message> <portType name="StockQuotePortType"> <operation name="SubscribeToQuotes"> <input message="tns:SubscribeToQuotes"/> </operation> </portType> <binding name="StockQuoteSoap" type="tns:StockQuotePortType"> <soap:binding style="document" transport="http://example.com/smtp"/> <operation name="SubscribeToQuotes"> <input message="tns:SubscribeToQuotes"> <soap:header element="xsd1:SubscriptionHeader"/> </input> </operation> </binding> <service name="StockQuoteService"> <port name="StockQuotePort" binding="tns:StockQuoteSoap"> <soap:address location="mailto://subscribe@example.com"/> </port> </service> <types> <schema targetNamespace="http://example.com/stockquote.xsd" xmlns="http://www.w3.org/1999/XMLSchema"> <element name="SubscribeToQuotes"> <complexType> <all> <element name="tickerSymbol" type="string"/> </all> </complexType> </element> <element name="SubscriptionHeader" type="uriReference"/> </schema> </types> </definitions>
该示例说明如何通过 SOAP 1.1 HTTP 绑定将 GetLastTradePrice SOAP 1.1 请求发送到 StockQuote 服务。该请求接受类型为字符串的 ticker 符号,类型为 timeInstant 的时间,并在 SOAP 响应中返回类型为浮点数的价格。
示例 4. 在 HTTP 之上运行的请求响应 RPC 操作的 SOAP 绑定
<?xml version="1.0"?> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote.wsdl" xmlns:tns="http://example.com/stockquote.wsdl" xmlns:xsd1="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <message name="GetLastTradePriceRequest"> <part name="tickerSymbol" element="xsd:string"/> <part name="time" element="xsd:timeInstant"/> </message> <message name="GetLastTradePriceResponse"> <part name="result" type="xsd:float"/> </message> <portType name="StockQuotePortType"> <operation name="GetLastTradePrice"> <input message="tns:GetLastTradePriceRequest"/> <output message="tns:GetLastTradePriceResponse"/> </operation> </portType> <binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="GetLastTradePrice"> <soap:operation soapAction="http://example.com/GetLastTradePrice"/> <input> <soap:body use="encoded" namespace="http://example.com/stockquote" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output> <soap:body use="encoded" namespace="http://example.com/stockquote" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation>> </binding> <service name="StockQuoteService"> <documentation>我的第一个服务</documentation> <port name="StockQuotePort" binding="tns:StockQuoteBinding"> <soap:address location="http://example.com/stockquote"/> </port> </service> </definitions>
SOAP 绑定使用下列扩展性元素对 WSDL 进行扩展:
<definitions…> <binding…> <soap:binding style="rpc|document" transport="uri"> <operation…> <soap:operation soapAction="uri"? style="rpc|document"?>? <input> <soap:body parts="nmtokens"? use="literal|encoded" encodingStyle="uri-list"? namespace="uri"?> <soap:header element="qname" fault="qname"?>* </input> <output> <soap:body parts="nmtokens"? use="literal|encoded" encodingStyle="uri-list"? namespace="uri"?> <soap:header element="qname" fault="qname"?>* </output> <fault>* <soap:fault name="nmtoken" use="literal|encoded" encodingStyle="uri-list"? namespace="uri"?> </fault> </operation> </binding> <port…> <soap:address location="uri"/> </port> </definitions>
将在下文中对 SOAP 绑定的这些扩展性元素分别加以详细说明。
此 SOAP 绑定元素用于表示绑定仅限于以下 SOAP 协议格式:信包、标头和正文。该元素没有声明消息的编码或格式(也就是说,它不一定遵循 SOAP 1.1 规范的第 5 节)。
使用 SOAP 绑定时,必须要有 soap:binding 元素。
<definitions…> <binding…> <soap:binding transport="uri"? style="rpc|document"?> </binding> </definitions>
style 属性的值是所包括的每个操作的样式属性的默认值。如果省略样式属性,则假定该属性为“document”。
transport 属性是必备属性,它的值表示此绑定与 SOAP 的哪种传输方式相对应。URI 值 http://schemas.xmlsoap.org/soap/http 与 SOAP 规范中的 HTTP 绑定相对应。此处还可以使用其它 URI,用于表示其它传输方式(如 SMTP、FTP 等)。
soap:operation 元素提供有关操作的总体信息。
<definitions…> <binding…> <operation…> <soap:operation soapAction="uri"? style="rpc|document"?> </operation> </binding> </definitions>
style 属性指定操作是面向 RPC 的(消息包含参数并返回值)还是面向文档的(消息包含文档)。该信息可以用于选择合适的编程模型。如果未指定此属性的值,则将默认为在 soap:binding 元素中指定的值。如果 soap:binding 元素没有指定样式,则假定其为“document”。
soapAction 属性指定该操作的 SOAPAction 标头值。此 URI 值应直接作为 SOAPAction 标头值使用。创建该请求时,请不要试图将相对 URI 值绝对化。对于 SOAP 的 HTTP 协议绑定,该值是必需的(它没有默认值)。对于其它 SOAP 协议绑定,可以不指定该值,同时也可以省略 soap:operation 元素。
soap:body 元素指定如何在 SOAP Body 元素中显示消息片段。
消息片段可以是抽象的类型定义,也可以是具体的架构定义。如果是抽象定义,类型将根据编码样式所定义的某些规则集进行序列化。与在 SOAP 规范中相同,每个编码样式都是使用一个 URI 列表来标识的。由于某些编码样式(如 SOAP 编码,http://schemas.xmlsoap.org/soap/encoding/)允许在一组给定的抽象类型中使用不同的消息格式,因此能否读懂所有这些格式变化将取决于消息的阅读器,即“阅读器处理法”。为了避免需要支持所有格式变化,可以对消息进行具体定义,然后指出其原始编码样式(如果有)作为提示。在这种情况下,消息的编写器必须完全符合指定的架构,即“编写器处理法”。
soap:body 元素既可用于定义面向 RPC 的消息,也可用于定义面向文档的消息。如果该元素所属操作的样式是“rpc”,则每个片段是一个参数或返回值,并出现在 Body 中的 wrapper 元素内部(请参见 SOAP 规范的第 7.1 节)。如果样式是“document”,则每个片段是一个文档,并直接出现在 Body 元素中。定义这两个元素 (Body 元素或 wrapper 元素) 的内容时,也使用相同的机制。
<definitions…> <binding…> <operation…> <input> <soap:body parts="nmtokens"? use="literal|encoded"? encodingStyle="uri-list"? namespace="uri"?> </input> <output> <soap:body parts="nmtokens"? use="literal|encoded"? encodingStyle="uri-list"? namespace="uri"?> </output> </operation> </binding> </definitions>
属于 nmtokens 类型的 parts 属性是可选属性,它指定哪些片段出现在消息的 SOAP Body 部分(其它消息片段可能会出现在该消息的其它部分,例如,当 SOAP 与多片段/相关 MIME 绑定一起使用时,会出现这种情况)。如果省略 parts 属性,则假定该消息定义的所有片段都包含在 SOAP Body 部分中。
use 属性是必备属性,它指定使用某种编码规则对消息片段进行编码,还是使用消息的具体架构来定义片段。
如果 use 属性的值为 encoded,则每个消息片段将使用 type 属性来引用抽象类型。通过应用由 encodingStyle 属性所指定的编码样式,可使用这些抽象类型生成具体的消息。虽然 namespace 属性只适用于不是由抽象类型明确定义的内容,但片段的 names、types 以及 namespace 属性的值都是该编码样式的输入值。如果引用的编码样式允许使用多种变化格式(例如,SOAP 编码就是这样),则必须支持所有格式变化(“阅读器处理法”)。
如果 use 属性的值为 literal,则每个片段使用 element 属性(对于简单片段)或 type 属性(对于复合片段)来引用具体架构。有关消息片段的详细信息,请参见第 2.3.1 节。可以使用 encodingStyle 属性的值来指定使用特定编码样式(如 SOAP 编码)派生具体格式,但是仅支持指定的格式变化(“编写器处理法”)。
encodingStyle 属性的值是由单个空格分隔的 URI 列表。这些 URI 代表在消息中使用的编码样式,按限制性由高到低的顺序排列(与在 SOAP 规范中定义的 encodingStyle 属性很相似)。
soap:fault 元素指定 SOAP Fault Details 元素的内容。
<definitions…> <binding…> <operation…> <fault>* <soap:fault name="nmtoken" use="literal|encoded" encodingStyle="uri-list"? namespace="uri"?> </fault> </operation> </binding> </definitions>
name 属性将 soap:fault 和为操作定义的 wsdl:fault 关联起来。
错误消息只能有一个片段。use、encodingStyle 和 namespace 属性的用法与它们在 soap:body 中的用法相同。
使用 soap:header 元素可以定义在 SOAP 信包的 Header 元素内传输的标头。没有必要在这一部分列出所有标头,因为在 WSDL 文档中指定其它内容时,通常会在有效负载中添加标头,因此不必在此处列出这些标头。
<definitions…> <binding…> <operation…> <input> <soap:header element="qname" fault="qname"?>* </input> <output> <soap:header element="qname" fault="qname"?>* </output> </operation> </binding> </definitions>
element 属性(类型为 QName)引用标头元素的具体架构。标头的架构不能包含 soap:actor 属性和 soap:mustUnderstand 属性的定义。
fault 属性是可选属性,它与 element 属性很相似。使用该属性可以在标头出现错误时,为该标头指定具体架构。SOAP 规范规定与标头有关的错误必须在标头中返回,而这个机制允许为这类标头指定架构。
SOAP 地址绑定用于为端口指定一个地址 (URI)。使用 SOAP 绑定的端口必须明确指定一个地址。
<definitions…> <port…> <binding…> <soap:address location="uri"/> </binding> </port> </definitions>
为了描述 Web 浏览器与 Web 站点之间的交互,WSDL 中包含了对 HTTP 1.1 的 GET 和 POST 谓词的绑定。这就使得除 Web 浏览器外,其它应用程序也可以与站点进行交互。可以指定以下协议专用信息:
- 指定绑定使用 HTTP GET 或 POST
- 端口地址
- 每个操作的相对地址(相对于端口定义的基址而言)
下例显示了为指定端口类型以不同方式绑定了三个端口。
如果传递的值是 part1=1、part2=2、part3=3,则每个端口的请求格式如下所示:
port1: GET, URL="http://example.com/o1/A1B2/3" port2: GET, URL="http://example.com/o1?p1=1&p2=2&p3=3 port3: POST, URL="http://example.com/o1", PAYLOAD="p1=1&p2=2&p3=3"
对于每个端口,响应均是一张 GIF 或 JPEG 图像。
示例 5. 使用 GET 与 FORM POST 返回 GIF 或 JPEG
<definitions…> <message name="m1"> <part name="part1" type="xsd:string"/> <part name="part2" type="xsd:int"/> <part name="part3" type="xsd:string"/> </message> <message name="m2"> <part name="image" type="xsd:binary"/> </message> <portType name="pt1"> <operation name="o1"> <input message="tns:m1"/> <output message="tns:m2"/> </operation> </portType> <service name="service1"> <port name="port1" binding="tns:b1"> <http:address location="http://example.com/"/> </port> <port name="port2" binding="tns:b1"> <http:address location="http://example.com/"/> </port> <port name="port3" binding="tns:b1"> <http:address location="http://example.com/"/> </port> </service> <binding name="b1" type="pt1"> <http:binding verb="GET"/> <operation name="o1"> <http:operation location="o1/A(part1)B(part2)/(part3)"/> <input> <http:urlReplacement/> </input> <output> <mime:content type="image/gif"/> <mime:content type="image/jpeg"/> </output> </operation> </binding> <binding name="b2" type="pt1"> <http:binding verb="GET"/> <operation name="o1"> <http:operation location="o1"/> <input> <http:urlEncoded/> </input> <output> <mime:content type="image/gif"/> <mime:content type="image/jpeg"/> </output> </operation> </binding> <binding name="b3" type="pt1"> <http:binding verb="POST"/> <operation name="o1"> <http:operation location="o1"/> <input> <mime:content type="application/x-www-form-urlencoded"/> </input> <output> <mime:content type="image/gif"/> <mime:content type="image/jpeg"/> </output> </operation> </binding> </definitions>
HTTP GET/POST 绑定使用下列扩展性元素对 WSDL 进行扩展:
<definitions…> <binding…> <http:binding verb="nmtoken"/> <operation…> <http:operation location="uri"/> <input…> <-- mime elements --> </input> <output…> <-- mime elements --> </output> </operation> </binding> <port…> <http:address location="uri"/> </port> </definitions>
将在下文中对这些元素进行介绍。
location 属性指定端口的基本 URI。该属性的值与 http:operation 绑定元素的 location 属性的值组合使用。
http:binding 元素表示此绑定使用 HTTP 协议。
<definitions…> <binding…> <http:binding verb="nmtoken"/> </binding> </definitions>
verb 属性是必备属性,其值指定 HTTP 谓词。常用的值是 GET 或 POST,但是也可以使用其它值。请注意,HTTP 谓词是区分大小写的。
location 属性指定操作的相对 URI。该 URI 与 http:address 元素中指定的 URI 组合在一起,构成 HTTP 请求的完整 URI。URI 值必须是相对 URI。
<definitions…> <binding…> <operation…> <http:operation location="uri"/> </operation> </binding> </definitions>
urlEncoded 元素表示使用标准 URI 编码规则 (name1=value&name2=value…) 将所有消息片段编码为 HTTP 请求 URI。参数的名称对应于消息片段的名称。片段所提供的每个值均使用一个 name=value 对进行编码。将其与 GET 一起使用可指定 URL 编码,与 POST 一起使用可指定 FORM-POST。对于 GET,将根据需要自动追加“?”字符。
<http:urlEncoded/>
http:urlReplacment 元素表示使用替换算法将所有消息片段编码为 HTTP 请求 URI:
- 按照一组搜索模式,搜索 http:operation 的相对 URI 值。
- 搜索发生在 http:operation 的值与 http:address 的 location 属性值组合之前。
- 每个消息片段都有一个搜索模式。搜索模式字符串是用括号“(”和“)”括起来的消息片段的名称。
- 对于每个匹配,将在匹配处用匹配值替换相应消息片段的值。
- 在执行匹配之后,才会替换值(替换的值不会触发其它匹配)。
消息片段不能具有重复值。
<http:urlReplacement/>
WSDL 提供一种方法,可将抽象类型绑定到某种 MIME 格式的具体消息。它为以下各类 MIME 定义了绑定:
- multipart/related
- text/xml
- application/x-www-form-urlencoded(在 HTML 中用于提交表单的格式)
- 其它(通过指定 MIME 类型字符串)
已定义的 MIME 类型很多,而且还在不断增加,因此 WSDL 没有必要为每种 MIME 类型都定义 XML 语法。必要时,可以添加其它语法来定义新的 MIME 类型。如果 MIME 类型字符串足以描述内容,则可以使用下面定义的 mime 元素。
示例 7. 将 multipart/related 与 SOAP 一起使用
此示例说明可以通过 SOAP 1.1 HTTP 绑定将 GetCompanyInfo SOAP 1.1 请求发送到 StockQuote 服务。该请求接受类型为字符串的 ticker 符号。而响应则包含以 MIME 格式 multipart/related 进行编码的多个片段:包含当前股票价格(类型为浮点数)的 SOAP 信包、HTML 格式的股票交易资料文档(可选)、GIF 或 JPEG 格式的公司徽标(可选)。
<definitions…> <types> <schema…> <element name="GetCompanyInfo"> <complexType> <all> <element name="tickerSymbol " type="string"/> </all> </complexType> </element> <element name="GetCompanyInfoResult"> <complexType> <all> <element name="result" type="float"/> </all> </complexType> </element> <complexType name="ArrayOfBinary" base="soap:Array"> <all> <element name="value" type="xsd:binary"/> </all> </complexType> </schema> </types> <message name="m1"> <part name="body" element="tns:GetCompanyInfo"/> </message> <message name="m2"> <part name="body" element="tns:GetCompanyInfoResult"/> <part name="docs" type="xsd:string"/> <part name="logo" type="tns:ArrayOfBinary"/> </message> <portType name="pt1"> <operation name="GetCompanyInfo"> <input message="m1"/> <output message="m2"/> </operation> </portType> <binding name="b1" type="tns:pt1"> <operation name="GetCompanyInfo"> <soap:operation soapAction="http://example.com/GetCompanyInfo"/> <input> <soap:body use="literal"/> </input> <output> <mime:multipartRelated> <mime:part> <soap:body parts="body" use="literal"/> </mime:part> <mime:part> <mime:content part="docs" type="text/html"/> </mime:part> <mime:part> <mime:content part="logo" type="image/gif"/> <mime:content part="logo" type="image/jpeg"/> </mime:part> </mime:multipartRelated> </output> </operation> </binding> <service name="CompanyInfoService"> <port name="CompanyInfoPort"binding="tns:b1"> <soap:address location="http://example.com/companyinfo"/> </port> </service> </definitions>
MIME 绑定使用下列扩展性元素对 WSDL 进行扩展:
<mime:content part="nmtoken"? type="string"?/> <mime:multipartRelated> <mime:part> * <-- mime element --> </mime:part> </mime:multipartRelated> <mime:mimeXml part="nmtoken"?/>
它们在 WSDL 中的以下位置出现:
<definitions…> <binding…> <operation…> <input…> <-- mime elements --> </input> <output…> <-- mime elements --> </output> </operation> </binding> </definitions>
出现在输入和输出部分下的 MIME 元素用于指定 MIME 格式。如果出现了多个这样的元素,则表示可以使用其中任何一个。
为了避免需要为每种 MIME 格式定义新的元素,在除 MIME 类型字符串外不再需要传送有关格式的其它信息时,可以使用 mime:content 元素。
<mime:content part="nmtoken"? type="string"?/>
part 属性用于指定消息片段的名称。如果消息只有一个片段,也可以不指定 part 属性。type 属性包含 MIME 类型字符串。type 值分为两部分,用斜杠 (/) 分隔,其中一个部分可以是通配符 (*)。如果没有指定 type 属性,则表示所有 MIME 类型都可以接受。
如果返回格式是 XML,而预先又不知道架构,则可以使用一般 mime 元素,表示类型为 text/xml:
<mime:content type="text/xml"/>
可以使用通配符 (*) 指定一系列 mime 类型,例如所有文本类型。
<mime:content type="text/*"/>
以下两个示例都指定了所有 mime 类型:
<mime:content type="*/*"/> <mime:content/>
multipart/related MIME 类型将任意一组由 MIME 格式化的片段聚合为一条使用 MIME 类型“multipart/related”的消息。mime:multipartRelated 元素描述该消息的具体格式:
<mime:multipartRelated> <mime:part> * <-- mime element --> </mime:part> </mime:multipartRelated>
mime:part 元素用于描述 multipart/related 消息的每个片段。mime:part 中出现的 MIME 元素指定片段的具体 MIME 类型。如果 mime:part 中出现了多个 MIME 元素,则表示可以使用其中任意一个。
将 MIME 绑定用于 SOAP 请求时,把 soap:body 元素作为 MIME 元素使用是合法的。它表示内容类型是“text/xml”,且包含在一个 SOAP 信包中。
对于不符合 SOAP(没有 SOAP 信包)但具有特定架构的 XML 有效负载,可以使用 mime:mimeXml 元素来指定其具体架构。part 属性指定义根 XML 元素的具体架构的消息片段。如果消息只有一个片段,则可以省略 part 属性。片段则使用 element 属性(对于简单片段)或 type 属性(对于复合片段)来引用具体的架构(请参见第 2.3.1 节)。
<mime:mimeXml part="nmtoken"?/>
[2] S. Bradner,“Key words for use in RFCs to Indicate Requirement Levels”,RFC 2119(英文),Harvard University,March 1997
[4] T. Berners-Lee,R. Fielding,L. Masinter,“Uniform Resource Identifiers (URI): Generic Syntax”,RFC 2396(英文),MIT/LCS,U.C. Irvine,Xerox Corporation,August 1998
[5] http://www.w3.org/TR/html401/interact/forms.html - submit-format(英文)
[6] http://www.w3.org/TR/html401/appendix/notes.html - ampersands-in-uris(英文)
[7] http://www.w3.org/TR/html401/interact/forms.html - h-17.13.4(英文)
[10] W3C Working Draft“XML Schema Part 1: Structures(英文)”。此文尚处于编写过程中。
[11] W3C Working Draft“XML Schema Part 2: Datatypes(英文)”。此文尚处于编写过程中。
本节的内容与此规范并没有直接关系,但所提供的背景资料在使用此规范的过程中可能会对您有所帮助。
XML 名称空间和架构的位置
人们经常将 XML 架构的 targetNamespace 或 XML 实例中的 xmlns 属性值与相应架构的位置混同起来。尽管名称空间实际上就是 URI,而 URI 可能就是位置,而且也可以从该位置检索到某个架构,但这并不表示只有这个架构与该名称空间相关联。可能有多个架构与特定的名称空间相关联,而在具体的处理环境中,到底使用哪个架构是由 XML 的处理器确定的。WSDL 规范通过 <import> 机制(该机制基于相似概念的 XML 架构语法)提供了这个处理环境。
在本文中,您会看到 WSDL 和 XSD 文档中使用了全限定 URI。使用全限定 URI 的目的只是为了说明相关概念。在很多情况下,完全可以使用相对 URI,且不会引起任何问题。有关处理相对 URI 的信息,请参见 http://www.normos.org/ietf/rfc/rfc2396.txt(英文)。
使用 WSDL 时,有时需要为某个实体创建一个 URI,但又不能让该 URI 始终都是全局唯一的,或让它“表示”该实体(架构、WSDL 文档等)的某个特定版本。对于这类行为,专门保留了特定的基本 URI 以供使用。基本 URI http://tempuri.org/ 可用于构建与实体没有任何唯一关联的 URI。例如,对于两个完全不同的架构,两个人或程序可以选择同时使用 URI http://tempuri.org/myschema。只要 URI 的使用范围不发生交叉,就可以认为它们是唯一的。这样做还有更进一步的好处:只要处理环境允许,无需生成新的 URI 就可以将该 URI 引用的实体版本化。但是,建议您不要将 http://tempuri.org/ 用作稳固实体的基本 URI。
示例 1
嵌入 HTTP 请求的 SOAP 消息
POST /StockQuote HTTP/1.1 Host: www.stockquoteserver.com Content-Type: text/xml; charset="utf-8" Content-Length: nnnn SOAPAction: "Some-URI" <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <m:GetLastTradePrice xmlns:m="Some-URI"> <symbol>DIS</symbol> </m:GetLastTradePrice> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
嵌入 HTTP 响应的 SOAP 消息
HTTP/1.1 200 OK Content-Type: text/xml; charset="utf-8" Content-Length: nnnn <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> <SOAP-ENV:Body> <m:GetLastTradePriceResponse xmlns:m="Some-URI"> <Price>34.5</Price> </m:GetLastTradePriceResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
扩展性元素可以出现在 WSDL 文档中的以下位置:
位置 | 含义 | 可能用法 |
definitions | 该扩展性元素适用于整个 WSDL 文档。 | · 将其它信息或定义引入整个 WSDL 文档。 |
definitions/types | 该扩展性元素是类型系统。 | · 使用除 XSD 以外的类型系统指定消息格式。 |
definitions/service | 该扩展性元素适用于服务。 | · 为服务引入其它信息或定义。 |
definitions/service/port | 该扩展性元素适用于端口。 | · 为端口指定地址。 |
definitions/binding | 该扩展性元素适用于整个绑定。 | · 提供适用于被绑定端口类型中所有操作的协议专用信息。 |
definitions/binding/operation | 该扩展性元素适用于整个操作。 | · 提供同时适用于输入消息和输出消息的协议专用信息。 |
definitions/binding/operation/input | 该扩展性元素适用于操作的输入消息。 | · 提供有关抽象消息片段如何映射为绑定的具体协议和数据格式的详细信息。 · 为输入消息提供其它协议专用信息。 |
definitions/binding/operation/output | 该扩展性元素适用于操作的输出消息。 | · 提供有关抽象消息片段如何映射为绑定的具体协议和数据格式的详细信息。 · 为输出消息提供其它协议专用信息。 |
definitions/binding/operation/fault | 该扩展性元素适用于操作的错误消息。 | · 提供有关抽象消息片段如何映射为绑定的具体协议和数据格式的详细信息。 · 为错误消息提供其它协议专用信息。 |
WSDL 架构
<schema targetNamespace="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/1999/XMLSchema" elementFormDefault="qualified"> <element name="documentation" > <complexType content="mixed"> <any minOccurs="0" maxOccurs="unbounded"/> <anyAttribute/> </complexType> </element> <complexType name="documented" abstract="true" content="elementOnly"> <element ref="wsdl:documentation"/> </complexType> <complexType name="openAtts" abstract="true" content="elementOnly"> <annotation> <documentation> 用组件类型来扩展此类型,以允许添加其它名称空间的属性。 </documentation> </annotation> <element ref="wsdl:documentation"/> <anyAttribute namespace="##other"/> </complexType> <element name="definitions" type="wsdl:definitionsType"> <key name="message"> <selector>message</selector> <field>@name</field> </key> <key name="portType"> <selector>portType</selector> <field>@name</field> </key> <key name="binding"> <selector>binding</selector> <field>@name</field> </key> <key name="service"> <selector>service</selector> <field>@name</field> </key> <key name="import"> <!-- 是否限制过多?--> <selector>import</selector> <field>@namespace</field> </key> <key name="port"> <selector>service/port</selector> <field>@name</field> </key> </element> <complexType name="definitionsType" base="wsdl:documented" derivedBy="extension"> <element ref="wsdl:import" minOccurs="0" maxOccurs="unbounded"/> <element ref="wsdl:types" minOccurs="0" maxOccurs="1"/> <element ref="wsdl:message" minOccurs="0" maxOccurs="unbounded"/> <element ref="wsdl:portType" minOccurs="0" maxOccurs="unbounded"/> <element ref="wsdl:binding" minOccurs="0" maxOccurs="unbounded"/> <element ref="wsdl:service" minOccurs="0" maxOccurs="unbounded"/> <any namespace="##other" minOccurs="0" maxOccurs="unbounded"> <annotation> <documentation>用于支持扩展性元素 </documentation> </annotation> </any> <attribute name="targetNamespace" type="uriReference" use="optional"/> <attribute name="name" type="NMTOKEN" use="optional"/> </complexType> <element name="import" type="wsdl:importType" /> <complexType name="importType" base="wsdl:documented" derivedBy="extension" > <attribute name="namespace" type="uriReference" use="required"/> <attribute name="location" type="uriReference" use="required"/> </complexType> <element name="types" type="wsdl:typesType"/> <complexType name="typesType" base="wsdl:documented" derivedBy="extension" > <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/> </complexType> <element name="message" type="wsdl:messageType"> <unique name="part"> <selector>part</selector> <field>@name</field> </unique> </element> <complexType name="messageType" base="wsdl:documented" derivedBy="extension"> <element ref="wsdl:part" minOccurs="0" maxOccurs="unbounded"/> <attribute name="name" type="NCName" use="required"/> </complexType> <element name="part" type="wsdl:partType"/> <complexType name="partType" base="wsdl:openAtts" derivedBy="extension"> <attribute name="name" type="NMTOKEN" use="optional"/> <attribute name="type" type="QName" use="optional"/> <attribute name="element" type="QName" use="optional"/> </complexType> <element name="portType" type="wsdl:portTypeType"> <key name="operation"> <selector>operation</selector> <field>@name</field> </key> </element> <complexType name="portTypeType" base="wsdl:documented" derivedBy="extension" content="elementOnly" > <element ref="wsdl:operation" minOccurs="0" maxOccurs="unbounded"/> <attribute name="name" type="NCName" use="required"/> </complexType> <element name="operation" type="wsdl:operationType"> <unique name="paramName"> <selector>input| output| fault</selector> <field>@name</field> </unique> </element> <complexType name="operationType" base="wsdl:documented" derivedBy="extension" > <choice minOccurs="1" maxOccurs="1"> <group ref="wsdl:one-way-operation"/> <group ref="wsdl:request-response-operation"/> <group ref="wsdl:solicit-response-operation"/> <group ref="wsdl:notification-operation"/> </choice> <attribute name="name" type="NCName" use="required"/> </complexType> <group name="one-way-operation"> <sequence> <element ref="wsdl:input" /> </sequence> </group> <group name="request-response-operation"> <sequence> <element ref="wsdl:input"/> <element ref="wsdl:output"/> <element ref="wsdl:fault" minOccurs="0" maxOccurs="unbounded"/> </sequence> </group> <group name="solicit-response-operation"> <sequence> <element ref="wsdl:output"/> <element ref="wsdl:input" /> <element ref="wsdl:fault" minOccurs="0" maxOccurs="unbounded"/> </sequence> </group> <group name="notification-operation"> <sequence> <element ref="wsdl:output"/> </sequence> </group> <element name="input" type="wsdl:paramType"/> <element name="output" type="wsdl:paramType"/> <element name="fault" type="wsdl:faultType"/> <complexType name="paramType" base="wsdl:documented" derivedBy="extension" > <attribute name="name" type="NMTOKEN" use="optional"/> <attribute name="message" type="QName" use="required"/> </complexType> <complexType name="faultType" base="wsdl:documented" derivedBy="extension" > <attribute name="name" type="NMTOKEN" use="required"/> <attribute name="message" type="QName" use="required"/> </complexType> <complexType name="startWithExtensionsType" base="wsdl:documented" derivedBy="extension" content="elementOnly" abstract="true"> <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/> </complexType> <element name="binding" type="wsdl:bindingType"/> <complexType name="bindingType" base="wsdl:startWithExtensionsType" derivedBy="extension" content="elementOnly"> <element name="operation" type="wsdl:binding_operationType" minOccurs="0" maxOccurs="unbounded"/> <attribute name="name" type="NCName" use="required"/> <attribute name="type" type="QName" use="required"/> </complexType> <complexType name="binding_operationType" base="wsdl:startWithExtensionsType" derivedBy="extension" content="elementOnly"> <element name="input" type="wsdl:startWithExtensionsType" minOccurs="0" maxOccurs="1"/> <element name="output" type="wsdl:startWithExtensionsType" minOccurs="0" maxOccurs="1"/> <element name="fault" minOccurs="0" maxOccurs="unbounded"> <complexType base="wsdl:startWithExtensionsType" derivedBy="extension"> <attribute name="name" type="NMTOKEN" use="required"/> </complexType> </element> <attribute name="name" type="NCName" use="required"/> </complexType> <element name="service" type="wsdl:serviceType"/> <complexType name="serviceType" base="wsdl:documented" derivedBy="extension" > <element ref="wsdl:port" minOccurs="0" maxOccurs="unbounded"/> <any namespace="##other" minOccurs="0" maxOccurs="1"/> <attribute name="name" type="NCName" use="required"/> </complexType> <element name="port" type="wsdl:portType"/> <complexType name="portType" base="wsdl:documented" derivedBy="extension"> <any namespace="##other" minOccurs="0" maxOccurs="1"/> <attribute name="name" type="NCName" use="required"/> <attribute name="binding" type="QName" use="required"/> </complexType> </schema>
OAP 绑定架构
<schema targetNamespace="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://www.w3.org/1999/XMLSchema"> <element name="binding" type="soap:bindingType"/> <complexType name="bindingType" content="empty"> <attribute name="transport" type="uriReference" use="optional"/> <attribute name="style" type="soap:styleChoice" use="optional"/> </complexType> <simpleType name="styleChoice" base="string" derivedBy="restriction"> <enumeration value="rpc"/> <enumeration value="document"/> </simpleType> <element name="operation" type="soap:operationType"/> <complexType name="operationType" content="empty"> <attribute name="soapAction" type="uriReference" use="optional"/> <attribute name="style" type="soap:styleChoice" use="optional"/> </complexType> <element name="body" type="soap:bodyType"/> <complexType name="bodyType" content="empty"> <attribute name="encodingStyle" type="uriReference" use="optional"/> <attribute name="parts" type="NMTOKENS" use="optional"/> <attribute name="use" type="soap:useChoice" use="optional"/> <attribute name="namespace" type="uriReference" use="optional"/> </complexType> <simpleType name="useChoice" base="string"> <enumeration value="literal"/> <enumeration value="encoded"/> </simpleType> <element name="fault" type="soap:faultType"/> <complexType name="faultType" base="soap:bodyType" derivedBy="restriction"> <attribute name="parts" type="NMTOKENS" use="prohibited"/> </complexType> <element name="header" type="soap:headerType"/> <complexType name="headerType" content="empty"> <attribute name="element" type="QName" use="required"/> <attribute name="fault" type="QName" use="optional"/> </complexType> <element name="address" type="soap:addressType"/> <complexType name="addressType" content="empty"> <attribute name="location" type="uriReference" use="required"/> </complexType> </schema>
HTTP 绑定架构
<schema targetNamespace="http://schemas.xmlsoap.org/wsdl/http/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns="http://www.w3.org/1999/XMLSchema"> <element name="address" type="http:addressType"/> <complexType name="addressType" content="empty"> <attribute name="location" type="uriReference" use="required"/> </complexType> <element name="binding" type="http:bindingType"/> <complexType name="bindingType" content="empty"> <attribute name="verb" type="NMTOKEN" use="required"/> </complexType> <element name="operation" type="http:operationType"/> <complexType name="operationType" content="empty"> <attribute name="location" type="uriReference" use="required"/> </complexType> <element name="urlEncoded"> <complexType content="empty"/> </element> <element name="urlReplacement"> <complexType content="empty"/> </element> </schema>
MIME 绑定架构
<schema targetNamespace="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns="http://www.w3.org/1999/XMLSchema"> <element name="content" type="mime:contentType"/> <complexType name="contentType" content="empty"> <attribute name="type" type="string" use="optional"/> <attribute name="part" type="NMTOKEN" use="optional"/> </complexType> <element name="multipartRelated" type="mime:multipartRelatedType"/> <complexType name="multipartRelatedType" content="elementOnly"> <element ref="mime:part" minOccurs="0" maxOccurs="unbounded"/> </complexType> <element name="part" type="mime:partType"/> <complexType name="partType" content="elementOnly"> <any namespace="targetNamespace" minOccurs="0" maxOccurs="unbounded"/> <attribute name="name" type="NMTOKEN" use="required"/> </complexType> <element name="mimeXml" type="mime:mimeXmlType"/> <complexType name="mimeXmlType" content="empty"> <attribute name="part" type="NMTOKEN" use="optional"/> </complexType> </schema>
要求响应操作的语法是:
使用 import 元素可以将服务定义的不同元素分别放入单独的文档中,需要时再将其导入。这种技术可以根据定义的抽象级别将其分开,这样有助于编写更为清晰的服务定义。使用这种技术还可以对各种服务定义进行最大限度的再利用。因此,具有这种结构的 WSDL 文档更易于使用和维护。在示例 2 中,我们将定义分为数据类型定义、抽象定义和特定服务绑定三类,并将其分别放入三个文档中。当然,这种机制的使用并不仅限于此例中明确出现的定义(这些定义只使用了本规范中所定义的语言元素),也可以使用类似的方式对基于其它语言扩展的其它定义类型进行编码和再利用。http://schemas.xmlsoap.org/wsdl/”。
示例 2. 示例 1 中所述服务的另一种撰写样式。
http://example.com/stockquote/stockquote.xsd