8.1.2 关于命名空间
函数ns1__getQuote(上节提到的)中,使用了ns1__作为远程方法的命名空间。使用命名空间是为了防止远程方法名冲突,比方多个服务中使用同一个远程方法名的情况。
命名空间前缀及命名空间名称同时也被用来验证SOAP信息的内容有效性。存根例程通过命名空间表中的信息来验证服务返回信息。命名空间表在运行时被取出用于解析命名空间绑定,反序列化数据结构,解码并验证服务返回信息。命名空间表不应该包含在gSOAP预编译器所需输入的头文件中。在18.2节中将会对命名空间表做详细介绍。
Delayed Stock Quote服务客户端的命名空间表如下:
struct Namespace namespaces[] =
{ // {"命名前缀", "空间名称"}
{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"}, // 必须是第一行
{"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/"}, // 必须是第二行
{"xsi", "http://www.w3.org/2001/XMLSchema-instance"}, // 必须是第三行
{"xsd", "http://www.w3.org/2001/XMLSchema"}, // 2001 XML 大纲
{"ns1", "urn:xmethods-delayed-quotes"}, // 通过服务描述获取
{NULL, NULL} // 结束
};
第一行命名空间是SOAP1.1协议默认命名空间。事实上,命名空间表就是用来让程序员可以规定SOAP编码方式,能够用包含命名空间的命名空间前缀来满足指定SOAP服务的命名空间需求的。举例来说,使用前面命名空间表中定义的命名空间前缀ns1,存根例程就可以对getQuote方法的请求进行编码。这个过程由gSOAP预编译器通过在getQuote.h文件中定义的包含前缀ns1的ns1__getQuote函数自动完成。通常,如果要在远程方法名,结构名,类名,字段名等结构或类中使用命名空间前缀,就必须在命名空间表中进行定义。
命名空间表将会被存根例程封装,并按下面的形式输出:
...
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ns1="urn:xmethods-delayed-quotes"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
...
这个命名空间绑定将被SOAP服务用来验证SOAP请求。
8.1.3 例子
使用命名空间前缀可以解决在不同的服务中使用相同名称的远程方法的问题,看下面的例子:
// Contents of file "getQuote.h":
int ns1__getQuote(char *symbol, float &Result);
int ns2__getQuote(char *ticker, char *"e);
这个例子允许客户端程序使用不同的命名空间以便连接到不同的服务程序执行其中的远程方法。
命名空间前缀也可以用在类声明中使用,在XML大纲中区分同名但不同命名空间的SOAP值。例如:
class e__Address // an electronic address
{
char *email;
char *url;
};
class s__Address // a street address
{
char *street;
int number;
char *city;
};
在生成的序列化函数中,使用e__Address的一个实例来表示e命名空间前缀的一个地址元素类型。
<e:Address xsi:type="e:Address">
<email xsi:type="string">me@home</email>
<url xsi:type="string">www.me.com</url>
</e:Address>
用s__Address的一个实例来表示s命名空间前缀的一个地址元素类型。
<s:Address xsi:type="s:Address">
<street xsi:type="string">Technology Drive</street>
<number xsi:type="int">5</number>
<city xsi:type="string">Softcity</city>
</s:Address>
客户端程序的命名空间表必须有e和s的数据类型定义:
struct Namespace namespaces[] =
{ ...
{"e", "http://www.me.com/schemas/electronic-address"},
{"s", "http://www.me.com/schemas/street-address"},
...
命名空间表必须作为客户端程序的一部分,使客户端程序在运行时可以对数据进行序列化及反序列化。