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

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

 

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

 

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

 

struct  ns1__ArrayOfString
{
        
int  __sizestring;        /*  sequence of elements <string>  */
        
char   ** string ;   /*  optional element of type xsd:string  */
};

 


但是,如果服务端返回的是一个相对复杂的结果集,事情就不那么好办了。例如,一个提供外汇汇率的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中搜索,可以发现其返回结果集最终的定义是:

 

struct  _ns1__getExchangeRateResponse_getExchangeRateResult
{
        
char   * xsd__schema;       /*  required element of type xsd:schema  */
        
char   * __any;
};

 

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

#include  < iconv.h >

#include 
" soapH.h "
#include 
" ExchangeRateWebServiceSoap12.nsmap "

int  conv_charset( const   char   * dest,  const   char   * src,  char   * input, size_t ilen,  char   * output, size_t olen) {
    iconv_t conv 
=  iconv_open(dest, src);
    
if  ( conv  ==  (iconv_t)  - 1  )
        
return   - 1 ;
    memset(output, 
0 , olen);
    
if  ( iconv(conv,  & input,  & ilen,  & output,  & olen) )
        
return   - 1 ;
    iconv_close(conv);
    
return   0 ;
}

int  main( int  argc,  char   ** argv) {
    
if  ( argc  !=   2   &&  argc  !=   3  ) {
        printf(
" Usage: %s type [end_point]\n " , argv[ 0 ]);
        printf(
" \ttype = A : all rate\n " );
        printf(
" \ttype = B : basic rate\n " );
        printf(
" \ttype = C : cross rate\n " );
        exit(
- 1 );
    }

    
struct  soap soap;
    soap_init(
& soap);
    
//  don't set is OK
    
// soap_set_mode(&soap, SOAP_C_UTFSTRING);

    
struct  _ns1__getExchangeRate request;
    
struct  _ns1__getExchangeRateResponse response;

    request.theType 
=  argv[ 1 ];
    
char   * endpoint  =  NULL;
    
if  ( argc  ==   3  )
        endpoint 
=  argv[ 2 ];
    
if  ( soap_call___ns3__getExchangeRate( & soap, endpoint, NULL,  & request,  & response)  ==  SOAP_OK ) {
        printf(
" %s\n " , response.getExchangeRateResult -> xsd__schema);
        printf(
" ----------\n " );
        
int  ilen  =  strlen(response.getExchangeRateResult -> __any);
        
int  olen  =  ilen  *   2 ;
        
char   * output  =  ( char   * ) malloc( sizeof ( char *  olen);
        conv_charset(
" GBK " " UTF-8 " , response.getExchangeRateResult -> __any, ilen, output, olen);
        printf(
" %s\n " , output);
        free(output);
    }
    
else  {
        soap_print_fault(
& soap, stderr);
    }

    soap_destroy(
& soap);
    soap_end(
& soap);
    soap_done(
& soap);
    
return   0 ;
}

#include <iconv.h> #include "soapH.h" #include "ExchangeRateWebServiceSoap12.nsmap" int conv_charset(const char *dest, const char *src, char *input, size_t ilen, char *output, size_t olen) { iconv_t conv = iconv_open(dest, src); if ( conv == (iconv_t) -1 ) return -1; memset(output, 0, olen); if ( iconv(conv, &input, &ilen, &output, &olen) ) return -1; iconv_close(conv); return 0; } int main(int argc, char **argv) { if ( argc != 2 && argc != 3 ) { printf("Usage: %s type [end_point]\n", argv[0]); printf("\ttype = A : all rate\n"); printf("\ttype = B : basic rate\n"); printf("\ttype = C : cross rate\n"); exit(-1); } struct soap soap; soap_init(&soap); // don't set is OK //soap_set_mode(&soap, SOAP_C_UTFSTRING); struct _ns1__getExchangeRate request; struct _ns1__getExchangeRateResponse response; request.theType = argv[1]; char *endpoint = NULL; if ( argc == 3 ) endpoint = argv[2]; if ( soap_call___ns3__getExchangeRate(&soap, endpoint, NULL, &request, &response) == SOAP_OK ) { printf("%s\n", response.getExchangeRateResult->xsd__schema); printf("----------\n"); int ilen = strlen(response.getExchangeRateResult->__any); int olen = ilen * 2; char *output = (char *) malloc(sizeof(char) * olen); conv_charset("GBK", "UTF-8", response.getExchangeRateResult->__any, ilen, output, olen); printf("%s\n", output); free(output); } else { soap_print_fault(&soap, stderr); } soap_destroy(&soap); soap_end(&soap); soap_done(&soap); return 0; }

其中,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差不多

 

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

 

#include  < iconv.h >
#include 
< libxml / parser.h >
#include 
< libxml / xmlmemory.h >

#include 
" soapH.h "
#include 
" ExchangeRateWebServiceSoap12.nsmap "

#define  FIELD_LEN 16

int  conv_charset( const   char   * dest,  const   char   * src,  char   * input, size_t ilen,  char   * output, size_t olen) {
    iconv_t conv 
=  iconv_open(dest, src);
    
if  ( conv  ==  (iconv_t)  - 1  )
        
return   - 1 ;
    memset(output, 
0 , olen);
    
if  ( iconv(conv,  & input,  & ilen,  & output,  & olen) )
        
return   - 1 ;
    iconv_close(conv);
    
return   0 ;
}

int  main( int  argc,  char   ** argv) {
    
if  ( argc  !=   2   &&  argc  !=   3  ) {
        printf(
" Usage: %s type [end_point]\n " , argv[ 0 ]);
        printf(
" \ttype = A : all rate\n " );
        printf(
" \ttype = B : basic rate\n " );
        printf(
" \ttype = C : cross rate\n " );
        exit(
- 1 );
    }

    
struct  soap soap;
    soap_init(
& soap);
    
//  don't set is OK
    
// soap_set_mode(&soap, SOAP_C_UTFSTRING);

    
struct  _ns1__getExchangeRate request;
    
struct  _ns1__getExchangeRateResponse response;

    request.theType 
=  argv[ 1 ];
    
char   * endpoint  =  NULL;
    
if  ( argc  ==   3  )
        endpoint 
=  argv[ 2 ];
    
if  ( soap_call___ns3__getExchangeRate( & soap, endpoint, NULL,  & request,  & response)  ==  SOAP_OK ) {
        
int  len  =  strlen(response.getExchangeRateResult -> __any);
        xmlDocPtr pdoc 
=  xmlParseMemory(response.getExchangeRateResult -> __any, len);
        xmlNodePtr root 
=  xmlDocGetRootElement(pdoc);
        xmlNodePtr curr 
=  root;
        
while  ( xmlStrcmp(curr -> name, ( const  xmlChar  * " getExchangeRate " ) )
            curr 
=  curr -> xmlChildrenNode;
        
for  ( curr  =  curr -> xmlChildrenNode; curr; curr  =  curr -> next ) {
            xmlNodePtr data;
            
for  ( data  =  curr -> xmlChildrenNode; data; data  =  data -> next ) {
                
char  ifield[FIELD_LEN];
                
char  ofield[FIELD_LEN];
                strcpy(ifield, xmlNodeGetContent(data));
                
if  ( conv_charset( " GBK " " UTF-8 " , ifield, strlen(ifield), ofield, FIELD_LEN) )
                    printf(
" %s\t%s\n " , data -> name, ifield);
                
else
                    printf(
" %s\t%s\n " , data -> name, ofield);
            }
            printf(
" \n " );
        }
        xmlFreeDoc(pdoc);
    }
    
else  {
        soap_print_fault(
& soap, stderr);
    }

    soap_destroy(
& soap);
    soap_end(
& soap);
    soap_done(
& soap);
    
return   0 ;
}

 


编译时,需要链接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


http://blog.csdn.net/yui/archive/2010/07/26/5767494.aspx

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