技术开发 频道

简单对象访问协议(SOAP)初级指南

  SOAP数据类型 

  在SOAP消息中,每个元素可能是一个SOAP结构元素,一个根元素,一个存取元素或一个独立的元素。在SOAP中,SOAP:Envelope,  SOAP:Body和  SOAP:Header  是唯一的三个结构元素。它们的基本关系由下列XML  Schema所描述:

<schema 
targetNamespace=''urn:schemas-xmlSOAP-org:SOAP.v1''> 
<element  name=''Envelope''> 
<type> 
<element  name=''Header''  type=''Header'' 
minOccurs=''0''  /> 
<element  name=''Body''  type=''Body'' 
minOccurs=''1''  /> 
</type> 
</element> 
</schema> 

  在SOAP元素的四种类型中,除了结构元素外都被用作表达类型的实例或对一个类型实例的引用。 

  根元素是显著的元素,它是SOAP:Body  或是  SOAP:Header的直接的子元素。其中SOAP:  Body只有一个根元素,它表达调用、响应或错误对象。这个根元素必须是SOAP:Body的第一个子元素,它的标记名和域名URI必须与HTTP  SOAPMethodName头或在错误消息情况下的SOAP:Fault相对应。而SOAP:Header元素有多个根元素,与消息相联系的每个头扩展对应一个。这些根元素必须是SOAP:Header的直接子元素,它们的标记名和名域URI表示当前存在扩展数据的类型。 

  存取元素被用作表达类型的域、属性或数据成员。一个给定类型的域在它的SOAP表达将只有一个存取元素。存取元素的标记名对应于类型的域名。考虑下列Java  类定义: 

package  com.bofSOAP.IBank; 
public  class  adjustment  { 
public  int  account  ; 
public  float  amount  ; 

在一个SOAP消息中被序列化的实例如下所示: 
<t:adjustment 
xmlns:t=''urn:develop-com:java:com.bofSOAP.IBank''> 
<account>3514</account> 
<amount>100.0</amount> 
</t:adjustment> 

  在这个例子中,存取元素account和amount被称着简单存取元素,因为它们访问对应于在W3C  XML  Schema规范  (见  http://www.w3.org/TR/XMLSchema-2)  的Part  2中定义的原始数据类型的值。这个规范指定了字符串,数值,日期等数据类型的名字和表达方式以及使用一个新的模式定义中的<datatype>结构来定义新的原始类型的机制。 

  对引用简单类型的存取元素,元素值被简单地编码为直接在存取元素下的字符数据,如上所示。对引用组合类型的存取元素(就是那些自身用子存取元素来构造的存取元素),有两个技术来对存取元素进行编码。最简单的方法是把被结构化的值直接嵌入在存取元素下。考虑下面的Java类定义: 

package  com.bofSOAP.IBank; 
public  class  transfer  { 
public  adjustment  from; 
public  adjustment  to; 


  如果用嵌入值编码存取元素,在SOAP中一个序列化的transfer对象如下所示: 

<t:transfer 
xmlns:t=''urn:develop-com:java:com.bofSOAP.IBank'' 

<from> 
<account>3514</account> 
<amount>-100.0</amount> 
</from> 
<to> 
<account>3518</account> 
<amount>100.0</amount> 
</to> 
</t:transfer> 

  在这种情况下,adjustment对象的值被直接编码在它们的存取元素下。 

  在考虑组合存取元素时,需要说明几个问题。先考虑上面的transfer类。类的from和to的域是对象引用,它可能为空。SOAP用XML  Schemas的null属性来表示空值或引用。下面例子表示一个序列化的transfer对象,它的from域是空的: 

<t:transfer 
xmlns:t=''urn:develop-com:java:com.bofSOAP.IBank'' 
xmlns:xsd=''http://www.w3.org/1999/XMLSchema/instance'' 

<from  xsd:null=''true''  /> 
<to> 
<account>3518</account> 
<amount>100.0</amount> 
</to> 
</t:transfer> 

  在不存在的情况下,  xsd:null属性的隐含值是false。给定元素的能否为空的属性是由XML  Schema定义来控制的。例如下列XML  Schema将只允许from存取元素为空: 

<type  name=''transfer''  > 
<element 
name=''from'' 
type=''adjustment'' 
nullable=''true'' 
/> 
<element 
name=''to'' 
type=''adjustment'' 
nullable=''false''  <!—  false  is  the  default  —> 
/> 
</type> 

  在一个元素的Schema声明中如果没有nullable属性,就意味着在一个XML文档中的元素是不能为空的。Null存取元素的精确格式当前还在修订中&#0;要了解用更多信息参考最新版本的SOAP规范。 

  与存取元素相关的另一个问题是由于类型关系引起的可代换性。由于前面的adjustment类不是一个final类型的类,transfer对象的from和to域实际引用继承类型的实例是可能的。为了支持这种类型兼容的替换,SOAP使用一个名域限定的类型属性的XML  Schema约定。这种类型属性的值是一个对元素具体的类型的限制的名字。考虑下面的adjustment扩展类: 

package  com.bofSOAP.IBank; 
public  class  auditedadjustment  extends  adjustment  { 
public  int  auditlevel; 


给出下面Java语言: 

transfer  xfer  =  new  transfer(); 
xfer.from  =  new  auditedadjustment(); 
xfer.from.account  =  3514;  xfer.from.amount  =  -100; 
xfer.from.auditlevel  =  3; 
xfer.to  =  new  adjustment(); 
xfer.to.account  =  3518;  xfer.from.amount  =  100; 

在SOAP中transfer对象的序列化形式如下所示: 

<t:transfer 
xmlns:xsd=''http://www.w3.org/1999/XMLSchema'' 
xmlns:t=''urn:develop-com:java:com.bofSOAP.IBank'' 

<from  xsd:type=''t:auditedadjustment''  > 
<account>3514</account> 
<amount>-100.0</amount> 
<auditlevel>3</auditlevel  > 
</from> 
<to> 
<account>3518</account> 
<amount>100.0</amount> 
</to> 
</t:transfer> 

  在这里xsd:type属性引用一个名域限定的类型名,它能被反序列化程序用于实例化对象的正确类型。因为to存取元素引用到一个被预料的类型的实例(而不是一个可代替的继承类型),xsd:type属性是不需要的。 

  刚才的transfer类设法回避了一个关键问题。如果正被序列化的transfer对象用下面这种方式初始化将会发生什么情况: 

transfer  xfer  =  new  transfer(); 
xfer.from  =  new  adjustment(); 
xfer.from.account  =  3514;  xfer.from.amount  =  -100; 
xfer.to  =  xfer.from; 

基于以前的议论,在SOAP  中transfer对象的序列化形式如下所示: 

<t:transfer 
xmlns:t=''urn:develop-com:java:com.bofSOAP.IBank''> 
<from> 
<account>3514</account> 
<amount>-100.0</amount> 
</from> 
<to> 
<account>3514</account> 
<amount>-100.0</amount> 
</to> 
</t:transfer> 

  这个表达有两个问题。首先最容易理解的问题是同样的信息被发送了两次,这导致了一个比实际所需要消息的更大的消息。一个更微妙的但是更重要的问题是由于反序列化程序不能分辨两个带有同样值的adjustment对象与在两个地方被引用的一个单一的adjustment对象的区别,两个存取元素间的身份关系就被丢失。如果这个消息接收者已经在结果对象上执行了下面的测试,(xfer.to  ==  xfer.from)将不会返回true。 

void  processTransfer(transfer  xfer)  { 
if  (xfer.to  ==  xfer.from) 
handleDoubleAdjustment(xfer.to); 
else 
handleAdjustments(xfer.to,  xfer.from); 


(xfer.to.equals(xfer.from))可能返回true的事实只是比较了两个存取元素的值而不是它们身份。 

  为了支持必须保持身份关系的类型的序列化,SOAP支持多引用存取元素。目前我们接触到的存取元素是单引用存取元素,也就是说,元素值是嵌入在存取元素下面的,而且其它存取元素被允许引用那个值(这很类似于在NDR中的[unique]的概念)。多引用存取元素总是被编码为只包含已知的SOAP:href属性的空元素。SOAP:href属性总是包含一个代码片段标识符,它对应于存取元素引用到的实例。如果to和from存取元素已经被编码为多引用存取元素,序列化的transfer对象如下所示: 

<t:transfer 
xmlns:t=''urn:develop-com:java:com.bofSOAP.IBank''> 
<from  SOAP:href=''#id1''  /> 
<to  SOAP:href=''#id1''  /> 
</t:transfer> 

  这个编码假设与adjustment类兼容的一个类型的实例已经在envelope中的其它地方被序列化,而且这个实例已经被用SOAP:id属性标记,如下所示: 

<t:adjustment  SOAP:id=''id1'' 
xmlns:t=''urn:develop-com:java:com.bofSOAP.IBank''> 
<account>3514</account> 
<amount>-100.0</amount> 
</t:adjustment> 

  对多引用存取元素,把代码段的标识符(例如#id1)分解到正确的实例是反序列化程序的工作。 

  前面的讨论解释了多引用存取元素怎样与它的目标实例相关联。下面要讨论的是目标实例在哪里被序列化。这就关系到独立元素和包的概念。

0
相关文章