soap简介

SOAP协议介绍及协议规范(一)
2008年03月03日 星期一 18:07
SOAP协议介绍及协议规范(一)

SOAP(Simple Object Access Protocol)简单对象访问协议SOAP是一个基于XML在分布式的环境中交换信息的简单的协议。SOAP为在一个松散的、分布式的环境中使用XML对等的交换结构化的和类型化的信息提供了一种简单的机制。SOAP本身并不定义任何应用语义,如编程模型或特定语义实现,它只是定义了一种简单的机制,通过一个模块化的包装模型和对模块中特定格式编码的数据的重编码机制来表示应用语义。

 

SOAP包括三个部分

SOAP封装envelop--结构定义了一个整体框架用来表示消息中包含什么内容,谁来处理这些内容以及这些内容是可选的或是必需的。
SOAP编码规则encoding rules--定义了用以交换应用程序定义的数据类型的实例的一系列机制。
SOAP RPC表示RPC representation --定义了一个用来表示远程过程调用和应答的协定。
虽然这三个部分都作为SOAP的一部分一起描述,但它们在功能上是相交的。特别的,封装和编码规则是在不同的名域中定义的,这种模块性的定义方法增加了简单性在SOAP封装,SOAP编码规则和SOAPRPC协定之外,这个规范还定义了两个协议的绑定binding ,描述了在有或没有HTTP扩展框架的情况下,SOAP消息如何包含在HTTP消息中被传送。

1。SOAP 的消息结构
一个SOAP envelope(强制元素)- 一个SOAP Header (可选元素)- 一个SOAP Body (强制元素):Body 为该消息的最终接收者所想得到的那些强制信息提供了一个容器- 此外,SOAP定义了Body的一个子元素Fault用于报告错误。

以下将举例说明:

在这个例子中,GetLastTradePrice SOAP 请求被发往StockQuote服务。这个请求携带一个字符串参数和ticker符号,在SOAP应答中返回一个浮点数。XML名域用来区分SOAP标志符和应用程序特定的标志符。如果SOAP中管理XML负载的规则完全独立于HTTP是没有意义的,因为事实上该负载是由HTTP携带的。

例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消息是其具体内容 :

例2 在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>

2. SOAP消息交换模型
SOAP消息从发送方到接收方是单向传送,但正如上面显示的,SOAP消息经常以请求/应答的方式实现。SOAP实现可以通过开发特定网络系统的特性来优化。例如,HTTP绑定使SOAP应答消息以HTTP应答的方式传输,并使用同一个连接返回请求。不管SOAP被绑定到哪个协议,SOAP消息采用所谓的“消息路径”发送,这使在终节点之外的中间节点可以处理消息。一个接收SOAP消息的SOAP应用程序必须按顺序执行以下的动作来处理消息:识别应用程序想要的SOAP消息的所有部分,检验应用程序是否支持第一步中识别的消息中所有必需部分并处理它。如果不支持,则丢弃消息。在不影响处理结果的情况下,处理器可能忽略第一步中识别出的可选部分。如果这个SOAP应用程序不是这个消息的最终目的地,则在转发消息之前删除第一步中识别出来的所有部分。为了正确处理一条消息或者消息的一部分,SOAP处理器需要理解:所用的交换方式(单向,请求/应答,多路发送等等),这种方式下接收者的任务,RPC机制(如果有的话)的使用,数据的表现方法或编码,还有其它必需的语义。尽管属性(比如SOAP encodingstyle)可以用于描述一个消息的某些方面,但这个规范并不强制所有的接收方也必须有同样的属性并取同样的属性值。举个例子,某一特定的应用可能知道一个元素表示一条遵循约定的RPC请求,但是另外一些应用可能认为指向该元素的所有消息都用单向传输,而不是类似请求应答模式。
(译者注:交互双方的SOAP消息并不一定要遵循同样的格式设定,而只需要以一种双方可理解的格式交换信息就可以了)

3. 与XML的关系
所有的SOAP消息都使用XML形式编码,一个SOAP应用程序产生的消息中,所有由SOAP定义的元素和属性中必须包括正确的名域。SOAP应用程序必须能够处理它接收到的消息中的SOAP名域,并且可以处理没有SOAP名域的SOAP消息,就象它们有正确的名域一样。

SOAP定义了两个名域
SOAP封装的名域标志符是 "http://schemas.xmlsoap.org/soap/envelope/"
SOAP的编码规则的名域标志符是 "http://schemas.xmlsoap.org/soap/encoding/"

SOAP消息中不能包含文档类型声明,也不能包括消息处理指令。SOAP使用"ID"类型"id"属性来指定一个元素的唯一的标志符,同时该属性是局部的和无需校验的。SOAP使用"uri-reference"类型的"href"属性指定对这个值的引用,同时该属性是局部的和无需校验的。这样就遵从了XML规范,XMLSchema规范和XML连接语言规范的风格。除了SOAP mustUnderstand 属性SOAPactor属性之外,一般允许属性和它们的值出现在XML文档实例或Schema中(两者效果相同)。也就是说,在DTD或Schema中声明一个缺省值或固定值和在XML文档实例中设置它的值在语义上相同。

4. SOAP封装
SOAP消息是一个XML文档,包括一个必需的SOAP封装,一个可选的SOAP头和一个必需的SOAP体。在这篇规范剩余部分中,提到SOAP消息时就是指这个XML文档。这一节中定义的元素和属性的名域标志符为:
"http://schemas.xmlsoap.org/soap/envelope/" 。
一个SOAP消息包括以下部分:
(1)在表示这个消息的XML文档中,封装是顶层元素。
(2)应用SOAP交换信息的各方是分散的且没有预先协定,SOAP头提供了向SOAP消息中添加关于这条SOAP消息的某些要素(feature)的机制。SOAP定义了少量的属性用来表明这项要素(feature)是否可选以及由谁来处理。
(3)SOAP体是包含消息的最终接收者想要的信息的容器。SOAP为SOAP体定义了一个Fault元素用来报告错误信息。

语法规则如下所示:

封装
元素名是 "Envelope"
在SOAP消息中必须出现
可以包含名域声明和附加属性。如果包含附加属性,这些属性必须限定名域。类似的,"Envelope"可以包含附加子元素,这些也必须限定名域且跟在SOAP体元素之后。

SOAP头
元素名是"Header"
在SOAP消息中可能出现。如果出现的话,必须是SOAP封装元素的第一个直接子元素。
SOAP头可以包含多个条目,每个都是SOAP头元素的直接子元素。所有SOAP头的直接子元素都必须限定名域。

SOAP体
元素名是"Body"
在SOAP消息中必须出现且必须是SOAP封装元素的直接子元素。它必须直接跟在SOAP头元素(如果有)之后。否则它必须是SOAP封装元素的第一个直接子元素。
SOAP体可以包括多个条目,每个条目必须是SOAP体元素的直接子元素。SOAP体元素的直接子元素可以限定名域。SOAP定义了SOAPFault元素来表示错误信息。

SOAP encodingstyle属性
Encodingstyle全局属性用来表示SOAP消息的序列化规则。这个属性可以在任何元素中出现,作用范围与名域声明的作用范围很相似,为这个元素的内容和它的所有没有重载此属性的子元素。SOAP消息没有定义缺省编码。属性值是一个或多个URI的顺序列表每个URI确定了一种或多种序列化规则,用来不同程度反序列化SOAP消息,举例如下:

"http://schemas.xmlsoap.org/soap/encoding/"
""

序列化规则由URI"http://schemas.xmlsoap.org/soap/encoding/" 确定。使用这个特定序列化规则的消息应该用encodingstyle属性说明这一点。另外,所有以"http://schemas.xmlsoap.org/soap/encoding/"开头的URI中的序列化规则与SOAP编码规则相一致。
一个零长度的URI("")明确显示所含元素没有任何编码形式。这可以用来取消上一级元素的所有编码声明。

封装版本模型
SOAP没有定义常规的基于主版本号和辅版本号的版本形式。SOAP消息必须有一个封装元素与名域"http://schemas.xmlsoap.org/soap/envelope/"关联。如果SOAP应用程序接收到的SOAP消息中的SOAP封装元素与其他的名域关联,则视为版本错误,应用程序必须丢弃这个消息。如果消息是通过HTTP之类的请求/应答协议收到的,应用程序必须回答一个SOAP VersionMismatch 错误信息。

SOAP头添加条目实现扩展

头元素编码为SOAP封装元素的第一个直接子元素。头元素的所有直接子元素称作条目。

条目的编码规则如下:
一个条目有它的完整的元素名(包括名域URI和局部名)确定。SOAP头的直接子元素必须有名域限制。
SOAP encodingstyle属性可以用来指示条目所用的编码形式
SOAP mustUnderstand属性和SOAPactor属性可以用来指示如何处理这个条目以及由谁来处理。

使用头属性
SOAP消息的接收者必须忽略所有不在SOAP头元素的直接子元素中SOAP头属性。下面的例子是一个SOAP头,包括一个元素标志符"Transaction","mustUnderstand"取值为"1"和数值5。这应该以如下方式编码:

<SOAP-ENV:Header>
<t:Transaction
xmlns:t="some-URI" SOAP-ENV:mustUnderstand="1">
5
</t:Transaction>
</SOAP-ENV:Header>

SOAP actor属性

SOAP actor全局属性可以用于指示头元素的接收者。SOAP actor属性的值是一个URI
URI "http://schemas.xmlsoap.org/soap/actor/next"指出了第一个处理这个消息的SOAP应用程序需要这个头元素。这类似于HTTP头中用Connection域表示hop-by-hop范围模型
省略SOAP actor属性表示接收者是SOAP消息的终节点。如果这个属性要生效,它必须出现在SOAP消息实例中。

SOAP mustUnderstand属性

SOAP mustUnderstand全局属性用来指示接受者在处理消息时这个条目是否必须处理。条目的接收者由SOAP actor属性定义。MustUnderstand属性的值是"1" 或 "0"。默认为“0”。值为“1”表示条目的接受者必须或者遵守语义(如以元素的全名传送)并按照语义正确的处理,或者放弃处理消息。SOAP mustUnderstand 属性考虑了消息演变的准确性(robust evolution)。必须假定包含SOAP mustUnderstand属性且值为"1"的元素以某种方式修改了它们的父元素或同层元素的语义。以这种方式连接元素确保了语义上的变化不会被那些不能完全理解它的接收者忽略。如果这个属性要生效,它必须出现在SOAP消息实例中。

SOAP错误

SOAP错误元素用于在SOAP消息中携带错误和(或)状态信息。如果有SOAP错误元素,它必须以以体条目的方式出现,并且在一个体元素中最多出现一次。SOAP错误元素定义了以下四个子元素:

faultcode
faultcode元素给软件提供了一个识别此错误的算法机制。SOAP错误元素必须有faultcode子元素,并且它的值必须是一个合法的名。
faultstring
faultstring元素提供了一个错误解释,而不是为了软件处理。faultstring元素类似于HTTP中定义的'Reason-Phrase'。SOAP错误元素必须有faultstring子元素,并且它应该提供一些错误本质的解释信息。
faultactor
faultactor元素提供了在消息路径上是谁导致了错误发生的信息。它类似于SOAP actor属性,只是SOAP actor指的是头条目的目的地,faultactor指的是错误的来源。faultactor属性的值是用来区分错误来源的URI。不是SOAP消息的最终目的地的应用程序必须在SOAP Fault元素中包含faultactor元素。消息的最终目的地可以使用faultactor元素明确的指示是它产生了这个错误
detail
detail元素用来携带与Body元素有关的应用程序所要的错误信息。如果Body元素的内容不能被成功的处理,则必须包含detail子元素。它不能用来携带属于头条目的错误信息。头条目的详细出错信息必须由头条目携带。Fault元素中没有detail元素表示这个错误与Body元素的处理无关。在有错误的时候,这可以用来区分Body元素有没有被正确的处理。detail元素的所有直接子元素称作detail条目,并且每个detail条目在detail元素中编码为独立的元素。
detail条目的编码规则如下:一个detail条目由它的元素全名(包括名域URI和局部名)确定。

SOAP 错误代码
定义的Faultcode值必须用在faultcode元素中。这些faultcode值的名域标志符为 "http://schemas.xmlsoap.org/soap/envelope/"。定义这个规范之外的方法时推荐(不要求)使用这个名域。缺省的SOAP faultcode值以可扩展的方式定义,允许定义新的SOAP faultcode值,并与现有的faultcode值向后兼容。使用的机制类似于HTTP中定义的1xx, 2xx,3xx等基本的状态类,不过,它们定义为XML合法名,而不是整数。字符"."(点)作为faultcode的分隔符,点左边的错误代码比右边的错误代码更为普通。如:
Client.Authentication

常见的faultcode值有:

名称                         含义
VersionMismatch 处理方发现SOAP封装元素有不合法的名域
MustUnderstand   处理方不理解或者不服从一个包含值为"1"的
mustUnderstand    属性的 SOAP头元素的直接子元素

Client     Client错误类表示消息的格式错误或者不包含适当的正确信息。

Server      Server错误类表示由于消息处理过程而不是消息内容本身使得消息不能正确的处理。

SOAP编码
SOAP编码格式基于一个简单的类型系统,概括了程序语言,数据库和半结构化数据等类型系统的共同特性。一个类型或者是一个简单的(标量的)类型,或者是由几个部分组合而成的复合类型,其中每个部分都有自己的类型。以下将详细描述这些类型。
这一节定义了类型化对象的序列化规则。它分两个层次。首先,给定一个与类型系统的符号系统一致的Schema(译者注:这里的schema不是符合XML语法的schema,而仅仅表示广义的用于表示消息结构的定义方式),就构造了XML语法的Schema。然后,给定一个类型系统的Schema和与这个Schema一致的特定的值,就构造了一个XML文档实例。反之,给定一个依照这些规则产生的XML文档实例和初始的Schema,就可以构造初始值的一个副本。这一节中定义的元素和属性的名域标志符为"http://schemas.xmlsoap.org/soap/encoding/"。下面的例子都假定在上一层的元素中声明了名域。
鼓励使用这一节中描述的数据模型和编码方式,但也可以在SOAP中使用其他的数据模型和编码方式。

XML中的编码类型规则
XML允许非常灵活的数据编码方式。SOAP定义了一个较小的规则集合。下面的术语用来描述编码规则:

一个"value"是一个字符串,类型(数字,日期,枚举等等)的名或是几个简单值的组合。所有的值都有特定的类型。
一个"simple value"没有名部分, 如特定的字符串,整数,枚举值等等。
一个"compound value"是相关的值的结合,如定单,股票报表,街道地址等等。在"compound value"中,每个相关的值都潜在的以名,序数或这两者来区分。这叫作"accessor"。复合值的例子有定单和股票报表等等。数组也是复合值。在复合值中,多个accessor有相同的名是允许的,例如RDF就是这样做的。
一个"array"是一个复合值,成员值按照在数组中的位置相互区分。
一个"struct"也是一个复合值,成员值之间的唯一区别是accessor名,accessor名互不相同。
一个"simple type"是简单值的类,如叫做"string" "integer"的类,还有枚举类等等。
一个"compound type"是复合值的类。复合类型的例子有定单类,它们有相同的accessor名(shipTo, totalCost等),但可能会有不同的值(可能以后被设置为确定的值)。
在复合类型中,如果类型内的accessor名互不相同,但是可能与其他类型中的accessor名相同,即,accessor名加上类型名形成一个唯一的标志符,这个名叫作"局部范围名"。如果名是直接或间接的基于URI的一部分,那么不管它出现在什么类型中,这个名本身就可以唯一标志这个accessor,这样的名叫作"全局范围名"。给定了schema中相关的值的序列化信息,就可能确定某些值只与某个accessor的一个实例有关。其它情况下则无法确定。当且仅当一个accessor引用一个值,这个值才能被视为"single-reference",如果有不止一个accessor引用它,那么就将它视为"multi-reference"。注意,可能一个确定的值在一个schema中是"single-reference",而在另一个schema中是"multi-reference"。在语句构成上,一个元素可能是"independent" 或 "embedded"。一个独立的元素指出现在序列化最顶层的任何元素。所有其它元素都是嵌入元素。虽然用xsi:type属性可以使值的结构和类型变为自描述的,但是序列化规则允许值的类型仅仅参照schema而定。这样的schema可能使用"XML Schema Part 1: Structures" [10]和"XML Schema Part 2: Datatypes" [11]中描述的符号系统,也可能使用其它符号系统。注意,虽然序列化规则可以用于除了数组和结构之外的复合类型,但是许多schema仅仅包含数组和结构类型。

序列化规则如下:

所有的值以元素内容的形式表示。一个multi-reference值必须表示为一个独立元素的内容,而一个single-reference值最好不要这样表示(也可以这样表示)。对于每个具有值的元素,值的类型时必须用下述三种方式之一描述:

所属元素实例有xsi:type属性
所属元素是一个有SOAP-ENC:arrayType 属性(该属性可能是缺省的)的元素的子元素,或者
所属元素的名具有特定的类型,类型可以由schema确定。
一个简单值表示为字符数据,即没有任何子元素。每个简单值必须具有一个类型。一个复合值编码成一个元素的序列,每个accessor用一个嵌入元素表示,该元素的元素名和accessor的名一致。如果accessor的名是局部于其所属的类型的,则该元素的元素名不是合格的,否则对应的元素名是合格的。
一个multi-reference的简单值或复合值编码成一个独立的元素,这个元素包含一个局部的无需校验的属性,属性名为"id",类型为"ID"(依照XML Specification [7])。值的每个accessor对应一个空元素,该元素有一个局部的,无需校验的属性,属性名为"href",类型为" uri-reference "(依照XML Schema Specification [11]),"href"属性的值引用了相对应的独立元素的URI标志符。字符串和字符数组表示为multi-reference的简单类型,但是特殊的规则使它们在普通的情况下能被更有效的表示。字符串和字符数组值的accessor可能有一个名字为"id",类型为"ID"(依照XML Specification [7])的属性。如果这样,所有这个值的所有其它accessor编码成一个空元素,这个元素有一个局部的,无需校验的属性,属性名为"href",类型为" uri-reference "(依照XML Schema Specification [11]),"href"属性的值引用了包含这个值的元素的URI标志符。编码时允许一个值有多个引用,就像多个不同的值有多个引用一样,但这仅在从上下文可以知道这个XML文档实例的含义没有改变时才可使用。数组是复合值。SOAP数组定义为具有类型"SOAP-ENC:Array"或从它衍生的类型.

SOAP数组可以时一维或多维,它们的成员以序数位置相互区分。一个数组值表示为反映这个数组的一系列元素,数组成员按升序出现。对多维数组来说,右边的这一维变化最快。每个成员元素命名为一个独立元素。(见规则2)SOAP数组可以是single-reference 或multi-reference值,因此可以表示为嵌入元素或独立元素的内容。SOAP数组必须包含一个"SOAP-ENC:arrayType" 属性,它的值指定了包含元素的类型和数组的维数。

"SOAP-ENC:arrayType"属性的值定义如下:

arrayTypevalue = atype asize
atype = QName *( rank )
rank = "[" *( "," ) "]"
asize = "[" #length "]"
length = 1*DIGIT

"atype"结构是被包含元素的类型名,它表示为QName并且作为类型限制在XML元素声明的
"type"属性中出现(这意味着被包含元素的所有值都要与该类型一致,即在SOAP-ENC:a rrayType中引用的类型必须是每个数组成员的类型或超类型)。在arrays of arrays or "jagged arrays"的情况下,类型组件编码为"innermost"类型且在从第一层开始的嵌套数组的每一层中,类型名后都跟随一个rank结构。多维数组编码时从第一维起,每一维之间用逗号隔开。
"asize"结构包含一个以逗号分隔的列表,数值0,1或其它整数表示数组每一维的长度。整数0表示没有指定详细的大小,但是可能在检查数组实际成员的大小后确定。例如,一个5个成员的整型数组的arrayTypevalue值为"int[][5]",它的atype值是int[]",asize值是"[5]"。同样,一个3个成员的两维整型数组的arrayTypevalue值为"int[,][3]",它的atype值是int[,]",asize值是"[3]"。
一个SOAP数组成员可能包含一个"SOAP-ENC:offset"属性表示这一项在整个数组中的位置偏移值。这被用来指示一个部分储值数组的位置偏移值。同样,一个数组成员可能包含一个"SOAP-ENC:position"属性表示这一项在整个数组中的位置,这被用来描述稀疏数组的成员。"SOAP-ENC:offset" 和"SOAP-ENC:position"属性值的定义如下:

arrayPoint = "[" #length "]"
偏移值和位置从0开始
NULL值或缺省值可能通过省略accssor元素来表示。NULL值也可能通过一个包含值为'1'的xsi:null属性的accssor元素来表示,其它的依赖于应用程序的属性和值也可能用来表示NULL值。注意,规则2允许独立的元素和数组成员名不同于值类型的元素。

简单类型
SOAP采用了"XML Schema Part 2: Datatypes"规范[11]"Built-in datatypes"节中的所有类型作为简单类型,包括值和取值范围。例如:

类型 举例
int 58502
float 314159265358979E+1
negativeInteger -32768
string Louis "Satchmo" Armstrong

在XML Schema规范中声明的数据类型可以直接用在元素schema中,也可以使用从这些类型衍生的新类型。一个schema和对应的具有这些类型的元素的数据实例的例子如下所示:

<element name="age" type="int"/>
<element name="height" type="float"/>
<element name="displacement" type="negativeInteger"/>
<element name="color">
<simpleType base="xsd:string">
<enumeration value="Green"/>
<enumeration value="Blue"/>
</simpleType>
</element>
<age>45</age>
<height>5.9</height>
<displacement>-450</displacement>
<color>Blue</color>

所有简单值必须编码为元素的内容,它的类型或者在"XML Schema Part 2: Datatypes"规范[11]中定义过,或者是基于一个用XML Schema规范提供的机制能推衍生出的类型。如果一个简单值编码为独立元素或异质数组成员,那么有一个对应于数据类型的元素声明将会很方便。因为"XML Schema Part 2: Datatypes"规范[11]包括了类型定义,但是不包括对应的元素声明,SOAP-ENC schema和名域为每个简单数据类型声明了一个元素,如<SOAP-ENC:int id="int1">45</SOAP-ENC:int>

字符串
字符串数据类型的定义在"XML Schema Part 2: Datatypes"规范[11]中。注意,这不同于许多数据库和程序语言中的"string"类型,特别的,字符串数据类型可能禁止某些在那些语言中允许的字符。(这些值必须用xsd:string之外的数据类型表示)一个字符串可能编码为一个single-reference 或 multi-reference值。包含字符串值的元素可能有一个"id"属性。附加的accessor元素可能有对应的"href"属性。
例如,同一字符串的两个accessor可能以如下形式出现:

<greeting id="String-0">Hello</greeting>
<salutation href="#String-0"/>

但是,如果两个accessor参考同一字符串实例(或字符串的子类型),这不是一个实质问题,它们可以编码为两个single-reference值,如下所示:

<greeting>Hello</greeting>
<salutation>Hello</salutation>

这个例子的schema片断如下所示:

<element name="greeting" type="SOAP-ENC:string"/>
<element name="salutation" type="SOAP-ENC:string"/>

在这个例子中,SOAP-ENC:string类型用作元素的类型,这是声明数据类型是"xsd:string"且允许"id" 和"href"属性的元素的简便方法。精确定义参见SOAP编码schema。Schemas可以使用这些源自SOAP编码schema的声明,但也可以不这样做。

Enumerations
"XML Schema Part 2: Datatypes"规范 [11] 定义了"enumeration."机制。SOAP数据模型直接采用了这种机制。但是,由于程序语言和其它语言在定义枚举时通常有些不同,所以我们在这里详细阐述了它的概念并描述了一个列表成员的可能取的值是如何编码的。"Enumeration"作为一个概念表示不同的名字的集合。一个特定的枚举就是对应于特定的基类型的不同的值的列表。例如,颜色集合("Green", "Blue", "Brown")可以定义为基于字符串类型的枚举,("1", "3", "5")可能是一个基于整型数的枚举,等等。"XML Schema Part 2: Datatypes" [11]支持除了布尔型以外所有简单类型的枚举。"XML Schema Part 1: Structures"规范[10]的语言可以用来定义枚举类型。如果schema由另一个没有特定基类型适用的符号系统生成,就使用"string"。在下面schema的例子中,"EyeColor"定义为字符串,可能的值是"Green", "Blue", 或"Brown"的枚举,数据实例按照schema显示如下。

<element name="EyeColor" type="tns:EyeColor"/>
<simpleType name="EyeColor" base="xsd:string">
<enumeration value="Green"/>
<enumeration value="Blue"/>
<enumeration value="Brown"/>
</simpleType>
<Person>
<Name>Henry Ford</Name>
<Age>32</Age>
<EyeColor>Brown</EyeColor>
</Person>

字符数组
一个字符数组可能编码为single-reference 或multi-reference值。字符数组的编码规则与字符串的编码规则类似。特别的,包含字符数组的元素值可能由一个"id"属性,附加的accssor元素可能有相应的"href"属性。推荐使用定义在XML Schemas [10][11]中的'base64'编码(使用在2045 [13]中定义的base64编码算法)表示模糊字符数组。不过,由于行长度(line length)的限制,通常在MIME中应用base64编码,SOAP中一般不应用base64编码。但是提供了"SOAP-ENC:base64"子类型使之能用于SOAP。

<picture xsi:type="SOAP-ENC:base64">
aG93IG5vDyBicm73biBjb3cNCg==
</picture>

多态accessor
许多语言允许能够多态访问多种类型值的accessor,每种类型在运行时可用。一个多态accessor实例必须包含一个"xsi:type"属性描述实际值的类型。例如,一个名为"cost"类型值为"xsd:float"的多态accessor编码如下:

<cost xsi:type="xsd:float">29.95</cost>与之对比,类型值不变的accessor编码如下:

<cost>29.95</cost>

Compound types复合类型
SOAP定义了与下列常在程序语言中出现的结构性模式对应的类型:

结构:一个"struct"是一个复合值,它的成员值的唯一区别是accessor名称,任意两个accessor名称都不相同。
数组:一个"array"是一个复合值,它的成员值的唯一区别是序数位置。
SOAP也允许结构和数组之外的其它数据的序列化,例如Directed-Labeled-Graph Data Model之类的数据中,单个节点有许多不同的accssor,有些不止出现一次。SOAP序列化规则不要求底层的数据模型在accssor之间区分次序,但如果有这样的次序的话,这些accssor必须按照这个顺序编码。

复合值,结构和值引用
复合值的成员编码为accessor元素。当accessor由名区分时(如结构),accessor名即作为元素名。名局部于类型的accessor有不受限的名,其它的accessor则有受限的名。下面的例子是类型为"Book"的结构:

<e:Book>
<author>Henry Ford</author>
<preface>Prefatory text</preface>
<intro>This is a book.</intro>
</e:Book>

以下是描述上面结构的schema片断:

<element name="Book">
<complexType>
<element name="author" type="xsd:string"/>
<element name="preface" type="xsd:string"/>
<element name="intro" type="xsd:string"/>
</complexType>
</e:Book>

以下是一个同时具有简单和复杂成员类型的例子。它显示两层引用。注意"Author"accssor元素的"href"属性是对相应具有"id"属性的值的引用。"Address"与之类似。

<e:Book>
<title>My Life and Work</title>
<author href="#Person-1"/>
</e:Book>
<e:Person id="Person-1">
<name>Henry Ford</name>
<address href="#Address-2"/>
</e:Person>
<e:Address id="Address-2">
<email>mailto:henryford@hotmail.com</email>
<web>
http://www.henryford.com<
;/web>
</e:Address>

当"Person"的值和"Address"的值是multi-reference时,上面的形式是正确的。如果它
们是single-reference,就必须用嵌入的形式,如下所示:

<e:Book>
<title>My Life and Work</title>
<author>
<name>Henry Ford</name>
<address>
<email>mailto:henryford@hotmail.com</email>
<web>
http://www.henryford.com<
;/web>
</address>
</author>
</e:Book>

如果添加一个限制,任意两个人都不会有相同的地址,并且地址可以是街道或Email地址,一本书可以有两个作者,编码如下:

<e:Book>
<title>My Life and Work</title>
<firstauthor href="#Person-1"/>
<secondauthor href="#Person-2"/>
</e:Book>
<e:Person id="Person-1">
<name>Henry Ford</name>
<address xsi:type="m:Electronic-address">
<email>mailto:henryford@hotmail.com</email>
<web>
http://www.henryford.com<
;/web>
</address>
</e:Person>
<e:Person id="Person-2">
<name>Samuel Crowther</name>
<address xsi:type="n:Street-address">
<street>Martin Luther King Rd</street>
<city>Raleigh</city>
<state>North Carolina</state>
</address>
</e:Person>

序列化可以包含对不在同一个资源的值的引用:

<e:Book>
<title>Paradise Lost</title>
<firstauthor href="http://www.dartmouth.edu/~milton/"/>
</e:Book>

以下是描述上面结构的schema片断:

<element name="Book" type="tns:Book"/>
<complexType name="Book">
<!-- Either the following group must occur or else the
href attribute must appear, but not both. -->
<sequence minOccurs="0" maxOccurs="1">
<element name="title" type="xsd:string"/>
<element name="firstauthor" type="tns:Person"/>
<element name="secondauthor" type="tns:Person"/>
</sequence>
<attribute name="href" type="uriReference"/>
<attribute name="id" type="ID"/>
<anyAttribute namespace="##other"/>
</complexType>
<element name="Person" base="tns:Person"/>
<complexType name="Person">
<!-- Either the following group must occur or else the
href attribute must appear, but not both. -->
<sequence minOccurs="0" maxOccurs="1">
<element name="name" type="xsd:string"/>
<element name="address" type="tns:Address"/>
</sequence>
<attribute name="href" type="uriReference"/>
<attribute name="id" type="ID"/>
<anyAttribute namespace="##other"/>
</complexType>
<element name="Address" base="tns:Address"/>
<complexType name="Address">
<!-- Either the following group must occur or else the
href attribute must appear, but not both. -->
<sequence minOccurs="0" maxOccurs="1">
<element name="street" type="xsd:string"/>
<element name="city" type="xsd:string"/>
<element name="state" type="xsd:string"/>
</sequence>
<attribute name="href" type="uriReference"/>
<attribute name="id" type="ID"/>
<anyAttribute namespace="##other"/>
</complexType>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值