使用gSOAP开发实例(5) libxml2解析SOAP响应消息

http://blog.csdn.net/yui/article/details/5767494


电信provisioning系统中,常常需要与远程服务器实时交换一些数据,以完成用户的请求。由于简单对象访问协议(Simple Object Access Protocol, SOAP)的流行,许多涉及到第三方的应用,我们一般都比较乐意使用SOAP来开发。不过,由于可能涉及到公司的机密,本系列教程的开发实例尽量采用在网上已经公开的Web Service资源。

 

前面四节的教程,分别采用了股票信息和天气预报的例子。而这两个实例有一个共同点,SOAP响应消息的数据结构相对简单,只需要按拟定的次序,事先约定返回数据代表的意义,就能够实现无歧义的沟通。这就使得gSOAP能够以字符串数组的形式,定义返回结果,再加上一个整型变量,指示返回结果的个数。

 

查看一下这两个实例的soapStub.h,可以发现,它们的结果集定义正是这样的:

 

 

[cpp]  view plain copy
  1. struct ns1__ArrayOfString  
  2. {  
  3.         int __sizestring;       /* sequence of elements <string> */  
  4.         char **string;  /* optional element of type xsd:string */  
  5. };  

但是,如果服务端返回的是一个相对复杂的结果集,事情就不那么好办了。例如,一个提供外汇汇率的Web Service,服务端会同时返回日元、瑞郎、英镑、欧元、澳元、加元、港币合计七种货币兑换美元的汇率情报,每种汇率情报又包括货币代码、当前汇率、涨跌幅、买入价、卖出价、时间戳等多个子项。显然,这不是一个线性结构,而是一个树形结构,就不能使用ArrayOfString来表示了。

 

这个案例的End point是:

http://webservice.webxml.com.cn/WebServices/ExchangeRateWebService.asmx

其WSDL是:

http://webservice.webxml.com.cn/WebServices/ExchangeRateWebService.asmx?wsdl

 

参考前面四节的内容,快速建立其存根程序,不再累述。

 

我们要实现的API是getExchangeRate,在soapStub.h中搜索,可以发现其返回结果集最终的定义是:

[cpp]  view plain copy
  1. struct _ns1__getExchangeRateResponse_getExchangeRateResult  
  2. {  
  3.         char *xsd__schema;      /* required element of type xsd:schema */  
  4.         char *__any;  
  5. };  

 

仅仅是两个字符串!于是,最初版本的外汇汇率客户端程序只能这样写:

[cpp]  view plain copy
  1. #include <iconv.h>  
  2.   
  3. #include "soapH.h"  
  4. #include "ExchangeRateWebServiceSoap12.nsmap"  
  5.   
  6. int conv_charset(const char *dest, const char *src, char *input, size_t ilen, char *output, size_t olen) {  
  7.     iconv_t conv = iconv_open(dest, src);  
  8.     if ( conv == (iconv_t) -1 )  
  9.         return -1;  
  10.     memset(output, 0, olen);  
  11.     if ( iconv(conv, &input, &ilen, &output, &olen) )  
  12.         return -1;  
  13.     iconv_close(conv);  
  14.     return 0;  
  15. }  
  16.   
  17. int main(int argc, char **argv) {  
  18.     if ( argc != 2 && argc != 3 ) {  
  19.         printf("Usage: %s type [end_point]/n", argv[0]);  
  20.         printf("/ttype = A : all rate/n");  
  21.         printf("/ttype = B : basic rate/n");  
  22.         printf("/ttype = C : cross rate/n");  
  23.         exit(-1);  
  24.     }  
  25.   
  26.     struct soap soap;  
  27.     soap_init(&soap);  
  28.     // don't set is OK  
  29.     //soap_set_mode(&soap, SOAP_C_UTFSTRING);  
  30.   
  31.     struct _ns1__getExchangeRate request;  
  32.     struct _ns1__getExchangeRateResponse response;  
  33.   
  34.     request.theType = argv[1];  
  35.     char *endpoint = NULL;  
  36.     if ( argc == 3 )  
  37.         endpoint = argv[2];  
  38.     if ( soap_call___ns3__getExchangeRate(&soap, endpoint, NULL, &request, &response) == SOAP_OK ) {  
  39.         printf("%s/n", response.getExchangeRateResult->xsd__schema);  
  40.         printf("----------/n");  
  41.         int ilen = strlen(response.getExchangeRateResult->__any);  
  42.         int olen = ilen * 2;  
  43.         char *output = (char *) malloc(sizeof(char) * olen);  
  44.         conv_charset("GBK""UTF-8", response.getExchangeRateResult->__any, ilen, output, olen);  
  45.         printf("%s/n", output);  
  46.         free(output);  
  47.     }  
  48.     else {  
  49.         soap_print_fault(&soap, stderr);  
  50.     }  
  51.   
  52.     soap_destroy(&soap);  
  53.     soap_end(&soap);  
  54.     soap_done(&soap);  
  55.     return 0;  
  56. }  

其中,xsd__schema没有中文字符,而__any含有中文字符,需要转换成GBK编码,具体可以参考前面两节。

 

编译执行,输出结果如下图:

 

使用gSOAP开发实例(5) libxml2解析SOAP响应消息_第1张图片

 

可以看出,服务端返回的两个长字符串实际上都是基于XML形式的。gSOAP能够自动帮我们完成的也就到此为止,剩下的需要我们自力更生了。

 

不过,大家也不用头疼,我们还有另外一个利器——libxml2!网上有很多关于libxml2的教程,所以我也不必多说,只要利用其中几个函数和语句即可。

 

1.     xmlParseMemory,字符串转为XML文档

2.     xmlDocGetRootElement,获取XML文档根节点

3.     xmlStrcmp,比较XML字符串,与strcmp差不多

4.     curr = curr->xmlChildrenNode,XML节点指针指向第一个子节点

5.     curr = curr->next,XML节点指针指向下一个兄弟节点

6.     xmlNodeGetContent,获取XML节点的内容

7.     xmlFreeDoc,释放节点,与free差不多

 

最终的外汇汇率客户端程序如下:

 

[cpp]  view plain copy
  1. #include <iconv.h>  
  2. #include <libxml/parser.h>  
  3. #include <libxml/xmlmemory.h>  
  4.   
  5. #include "soapH.h"  
  6. #include "ExchangeRateWebServiceSoap12.nsmap"  
  7.   
  8. #define FIELD_LEN 16  
  9.   
  10. int conv_charset(const char *dest, const char *src, char *input, size_t ilen, char *output, size_t olen) {  
  11.     iconv_t conv = iconv_open(dest, src);  
  12.     if ( conv == (iconv_t) -1 )  
  13.         return -1;  
  14.     memset(output, 0, olen);  
  15.     if ( iconv(conv, &input, &ilen, &output, &olen) )  
  16.         return -1;  
  17.     iconv_close(conv);  
  18.     return 0;  
  19. }  
  20.   
  21. int main(int argc, char **argv) {  
  22.     if ( argc != 2 && argc != 3 ) {  
  23.         printf("Usage: %s type [end_point]/n", argv[0]);  
  24.         printf("/ttype = A : all rate/n");  
  25.         printf("/ttype = B : basic rate/n");  
  26.         printf("/ttype = C : cross rate/n");  
  27.         exit(-1);  
  28.     }  
  29.   
  30.     struct soap soap;  
  31.     soap_init(&soap);  
  32.     // don't set is OK  
  33.     //soap_set_mode(&soap, SOAP_C_UTFSTRING);  
  34.   
  35.     struct _ns1__getExchangeRate request;  
  36.     struct _ns1__getExchangeRateResponse response;  
  37.   
  38.     request.theType = argv[1];  
  39.     char *endpoint = NULL;  
  40.     if ( argc == 3 )  
  41.         endpoint = argv[2];  
  42.     if ( soap_call___ns3__getExchangeRate(&soap, endpoint, NULL, &request, &response) == SOAP_OK ) {  
  43.         int len = strlen(response.getExchangeRateResult->__any);  
  44.         xmlDocPtr pdoc = xmlParseMemory(response.getExchangeRateResult->__any, len);  
  45.         xmlNodePtr root = xmlDocGetRootElement(pdoc);  
  46.         xmlNodePtr curr = root;  
  47.         while ( xmlStrcmp(curr->name, (const xmlChar *) "getExchangeRate") )  
  48.             curr = curr->xmlChildrenNode;  
  49.         for ( curr = curr->xmlChildrenNode; curr; curr = curr->next ) {  
  50.             xmlNodePtr data;  
  51.             for ( data = curr->xmlChildrenNode; data; data = data->next ) {  
  52.                 char ifield[FIELD_LEN];  
  53.                 char ofield[FIELD_LEN];  
  54.                 strcpy(ifield, xmlNodeGetContent(data));  
  55.                 if ( conv_charset("GBK""UTF-8", ifield, strlen(ifield), ofield, FIELD_LEN) )  
  56.                     printf("%s/t%s/n", data->name, ifield);  
  57.                 else  
  58.                     printf("%s/t%s/n", data->name, ofield);  
  59.             }  
  60.             printf("/n");  
  61.         }  
  62.         xmlFreeDoc(pdoc);  
  63.     }  
  64.     else {  
  65.         soap_print_fault(&soap, stderr);  
  66.     }  
  67.   
  68.     soap_destroy(&soap);  
  69.     soap_end(&soap);  
  70.     soap_done(&soap);  
  71.     return 0;  
  72. }  

 

编译时,需要链接libxml2库,同时指定头文件所在路径:

gcc -O2 -o exchange exchange.c soapC.c soapClient.c ../../stdsoap2.c -I../.. -I/usr/include/libxml2 -L../.. -lgsoap -lxml2

 

执行结果(部分)如下:

 

-bash-3.2$ ./exchange B

Code    JPY

Currency        日元

ClosePrice      87.08

DiffPercent     -0.29%

DiffAmount      -0.25

OpenPrice       87.5

HighPrice       87.71

LowPrice        87.04

Range   0.77%

BuyPrice        87.08

SellPrice       87.12

ChangeColor     Green

DataTime        16:57:54

 

Code

CHF

Currency        瑞郎

ClosePrice      1.0552

DiffPercent     0.16%

DiffAmount      0.0017

OpenPrice       1.054

HighPrice       1.0552

LowPrice        1.0498

Range   0.51%

BuyPrice        1.0552

SellPrice       1.0556

ChangeColor     Red

DataTime        16:57:52


你可能感兴趣的:(使用gSOAP开发实例(5) libxml2解析SOAP响应消息)