zoukankan      html  css  js  c++  java
  • gSoap实现ONVIF中xsd__anyType到具体结构类型的转换

    上一篇文章已经粗略计划要讨论gsoap关于序列化/解析编程。

    本文则阐述一下关于gsoap生成代码的一些重要特征方法及使用。如题,下我们从ONVIF生成的C码中,挑选简单的一个类型来试验一下与xsd__anyType之间的转换。这个试验如此重要,主要是因为,在之前我真的拿生成代码的相关结构的的一些__any字段没有办法。虽依据ONVIF文档,以及实际交互观测的XML结构中可知明明是已知的标准结构,却无奈生成被解析成any字段,主要是可能这部分字段可由厂商决定填充哪些扩展意义的结构。

    简单试验

    本次试验选_trt__GetProfile结构作转换例程,主要理由是这个结构实在简单,只含有一个字段;书写初始化简单。

    struct _trt__GetProfile

    #soapStub.h

    #ifndef SOAP_TYPE__trt__GetProfile
    #define SOAP_TYPE__trt__GetProfile (1365)
    /* trt:GetProfile */
    struct _trt__GetProfile
    {
    	char *ProfileToken;	/* required element of type tt:ReferenceToken */
    };
    #endif
    

    头部概览与FD操作

    #include "inc.h"
    typedef struct soap *soap_pointer;
    #include "soap.nsmap"
    
    // anyType
    int anyType_ready(void)
    {
    	return open("anyType.xml", O_RDWR|O_CREAT, S_IWUSR|S_IRUSR);
    }
    int FD_set(int* FD, int fd)
    {
    	int ret = *FD; *FD = fd;
    	return ret;
    }
    

    注:inc.h是自组织的部分所需头依赖;

    后面包含了soap.nsmap文件,你懂的,里面解开可以可以依次了解清楚包含与依赖关系;

    soap.nsmap < soapH.h < soapStub.h < stdsoap2.h

    主流程 main()

    static xsd__anyType* _trt__GetProfile2anyType(soap_pointer soap_, struct _trt__GetProfile* p_, xsd__anyType* _any);
    static struct _trt__GetProfile*
    _trt__GetProfile_from_anyType(soap_pointer soap_, struct _trt__GetProfile* _p, xsd__anyType* _any);
    
    int main(int argc, char const *argv[])
    {
    	/* code */
    	struct soap soap;
    	soap_pointer soap_ = &soap;
    	soap_init(soap_);
    	struct _trt__GetProfile Data = {"Profile0"};
    	xsd__anyType Dom; soap_default_xsd__anyType(soap_, &Dom);
    	if (_trt__GetProfile2anyType(soap_, &Data, &Dom))
    	{
    		soap_default__trt__GetProfile(soap_, &Data);
    		if (_trt__GetProfile_from_anyType(soap_, &Data, &Dom))
    			printf("Data >%s", Data.ProfileToken);
    	}
    	soap_end(soap_);soap_done(soap_);
    	return 0;
    }
    

    具体转换实现

    xsd__anyType* _trt__GetProfile2anyType( soap_pointer soap_, struct _trt__GetProfile* p_, xsd__anyType* _any )
    {
    	int fd = anyType_ready();
    	bool b = (fd == -1);
    	if (b) return NULL;
    	do {
    		int* FD = &(soap_->sendfd);
    		fd = FD_set(FD, fd);
    		b  = (soap_write__trt__GetProfile(soap_, p_) != SOAP_OK);
    		fd = FD_set(FD, fd);
    		b = b &&(lseek(fd, 0, SEEK_SET) == -1);
    		if (b) break;
    		FD = &(soap_->recvfd);
    		fd = FD_set(FD, fd);
    		b  = (soap_read_xsd__anyType(soap_, _any) != SOAP_OK);
    		fd = FD_set(FD, fd);
    	} while(false);
    	close(fd);
    	if (b) return NULL;
    	return _any;
    }
    struct _trt__GetProfile* _trt__GetProfile_from_anyType(soap_pointer soap_,
    struct _trt__GetProfile* _p, xsd__anyType* _any)
    {
    	int fd = anyType_ready();
    	bool b = (fd == -1);
    	if (b) return NULL;
    	do {
    		int* FD = &(soap_->sendfd);
    		fd = FD_set(FD, fd);
    		b  = (soap_write_xsd__anyType(soap_, _any) != SOAP_OK);
    		fd = FD_set(FD, fd);
    		b = b &&(lseek(fd, 0, SEEK_SET) == -1);
    		if (b) break;
    		FD = &(soap_->recvfd);
    		fd = FD_set(FD, fd);
    		b  = (soap_read__trt__GetProfile(soap_, _p) != SOAP_OK);
    		fd = FD_set(FD, fd);
    	} while(false);
    	close(fd);
    	if (b) return NULL;
    	return _p;
    }

    参考相关

    本次试验启发于gsoap指南

    gSOAP 2.8.11 User Guide

    7.5.3 Serializing C/C++ Data to XML

    You can assign an output stream to soap.os or a le descriptor to soap.sendfd. For example

    soap.sendfd = open(file, O_RDWR|O_CREAT, S_IWUSR|S_IRUSR);
    soap_serialize_PointerTons_Person(&soap, &p);
    soap_begin_send(&soap);
    soap_put_PointerTons_Person(&soap, &p, "ns:element-name", "ns:type-name");
    soap_end_send(&soap);

    The above can be abbreviated to

    soap.sendfd = open(file, O_RDWR|O_CREAT, S_IWUSR|S_IRUSR);
    soap_write_PointerTons_Person(&soap, &p);

    gSoap生成代码的重要使用特征

    生成清单

    • soapStub.h
    • soapClient.c
    • soapH.h
    • soapC.c
    • soap.nsmap

    这是客户端的生成简单,soapClient.c 是soapStub.h的实现, soapC.c是soapH.h的实现,soap.nsmap是定义全局编译所需的xmlns集合namespaces[];

    我们主要通过调用soapStub.h声明的方法来完成Service的访问,其中封装了交互过程;所有结构都定义在soapStub.h中有声明;

    当然soapH.h则对应每一个结构都生成了相应的序列化/解析的方法,以及一些读写宏。

    soapStub.h

    所有交互命令的调用及结构声明;

    soapH.h

    #ifndef SOAP_TYPE_xsd__duration
    #define SOAP_TYPE_xsd__duration (190)
    #endif
    SOAP_FMAC1 void SOAP_FMAC2 soap_default_xsd__duration(struct soap*, LONG64 *);
    
    SOAP_FMAC3S const char* SOAP_FMAC4S soap_xsd__duration2s(struct soap*, LONG64);
    SOAP_FMAC1 int SOAP_FMAC2 soap_out_xsd__duration(struct soap*, const char*, int, const LONG64 *, const char*);
    
    SOAP_FMAC3S int SOAP_FMAC4S soap_s2xsd__duration(struct soap*, const char*, LONG64 *);
    SOAP_FMAC1 LONG64 * SOAP_FMAC2 soap_in_xsd__duration(struct soap*, const char*, LONG64 *, const char*);
    
    SOAP_FMAC3 int SOAP_FMAC4 soap_put_xsd__duration(struct soap*, const LONG64 *, const char*, const char*);
    
    #ifndef soap_write_xsd__duration
    #define soap_write_xsd__duration(soap, data) ( soap_serialize_xsd__duration(soap, data), soap_begin_send(soap) || soap_put_xsd__duration(soap, data, "xsd:duration", NULL) || soap_end_send(soap), soap->error )
    #endif
    
    SOAP_FMAC3 LONG64 * SOAP_FMAC4 soap_get_xsd__duration(struct soap*, LONG64 *, const char*, const char*);
    
    #ifndef soap_read_xsd__duration
    #define soap_read_xsd__duration(soap, data) ( soap_begin_recv(soap) || !soap_get_xsd__duration(soap, data, NULL, NULL) || soap_end_recv(soap), soap->error )
    #endif
    


    我们能见到大量类似这样规则的定义,每个方法的前置宏声明是有区别意义的。

    SOAP_FMAC3S 这是序列化成字符串的方法修饰;这类方法主要是一类简单的基本类型到字符串的序列化转换, 比如ONVIF中有定义许多的枚举;

    具体这么多修饰宏的意义可以参照stdsoap2.h中描述,在VC环境下使用助手的outline功夫查看文件代码结构是相当直观的。

    另外我们还看见每一种类型都定义了soap_read/write_***的函式宏,本文试验主要就是通过这类读写来实现不同实现结构的转换的。

    标准化

    总之,为了工作简洁高效,日后可读可维护,我们尽量使用标准化的调用方式,而不走偏方,这才是本文针对各编程界提倡的建议。

  • 相关阅读:
    提纲挈领webrtc之vad检测
    提纲挈领webrtc音频处理算法之写在前面的话
    搭建git远程服务器三步骤
    详解m4文件
    chrome浏览器被reimage pair 劫持怎么处理
    linux查看系统32位还是64位
    git gc和fsck的用法
    ubuntu 16.04 的64位 安装arm-none-linux-gnueabi-gcc的步骤和问题解决
    利用终端命令实现进入ntfs分区有两种方法。
    ubuntu-14.10下,安装gcc交叉编译器遇到问题及解决方法
  • 原文地址:https://www.cnblogs.com/qianwen36/p/3947454.html
Copyright © 2011-2022 走看看