与存取元素相关的另一个问题是由于类型关系引起的可代换性。由于前面的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)分解到正确的实例是反序列化程序的工作。
前面的讨论解释了多引用存取元素怎样与它的目标实例相关联。下面要讨论的是目标实例在哪里被序列化。这就关系到独立元素和包的概念。
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)分解到正确的实例是反序列化程序的工作。
前面的讨论解释了多引用存取元素怎样与它的目标实例相关联。下面要讨论的是目标实例在哪里被序列化。这就关系到独立元素和包的概念。