gsoap入门:Schema类型映射塈将xsd:date类型转为struct tm

本文介绍如何通过修改typemap.dat文件来自定义xsd:date类型与C/C++中struct tm类型的映射关系,以实现更精确的数据转换。

typemap.dat的作用

在使用wsdl2h生成.h文件时,有一个参数-t 用于指定typemap.dat,如果你不指定这个参数,wsdl2h也能正常执行,后续soapcpp2也能正常生成c/c++代码.那么这个typemap.dat有什么用呢?

根据gsoap官网的解释,typename.dat是类型映射定义文件,用于定义schema 类型和c/c++类型的之间的对应关系,比如:
xsd:string对应c++的std::string,
xsd:xsd__double对应c/c++中的double
。。。

这些显而易见的类型映射都不需要我们手工指定。所以你在执行wsdl2h时即使不指定-t参数,wsdl2h会使用默认的typemap.dat,也能将schema 类型转换c/c++类型。
$gsoap/gosap/typemap.dat就是wsdl2h使用的默认类型映射文件。
打开这个文本文件,有详细的说明。内容太长就不全部贴出来了,根据说明,我们可以通过修改这个文件,改变schema 类型和c/c++ 类型之间默认的映射关系 。

将xsd:date映射为struct tm

现在就以xsd:date为例,来说说如何自定义typemap.dat

如果你的webservice接口中有传递xsd:date类型的数据,当你不加-t参数执行wsdl2h并用soapcpp2生成c++代码时。你会发现xsd:date类型的数据默认被转成了std::string类型。(我们的webservice是基于java的axis2。所以java.util.Date对象自动被映射成了xsd:date。到了gsoap客户端就成了std::string

如果你希望gsoap在进行数据序列化和反序列化时自动将xsd:date转为c/c++标准的struct tm结构,就需要修改或自定义typemap.dat,重新生成c/c++代码。具体的步骤如下。

修改typemap.dat

打开$gsoap/gosap/typemap.dat,搜索"xsd:date"找到下面这段被#注释的文本,如下图删除注释符。
这里写图片描述

参见《8.2 Customizing Data Bindings With The typemap.dat File》
typemap.dat就算修改完了,你可以将这一行保存到一个新文件中,也可以保存修改直接在后续使用这个文件。

重新生成c/c++代码

执行wsdl2h编译生成.h文件,用-t参数指定刚才修改的typemap.dat文件,我在这里是将修改的那一行数据保存到新文件mytypemap.dat

wsdl2h -t mytypemap.dat -o facedbservice.h http://gdface.wicp.net:15865/axis2/services/FaceDbService?wsdl

执行soapcpp2生成c/c++代码:

soapcpp2 -C -L -x -pfacedbservice -IJ:\gsoap-2.8\gsoap\import;J:\gsoap-2.8\gsoap facedbservice.h

这里-I参数指定了J:\gsoap-2.8\gsoap为gsoap的安装路径,这样,soapcpp2在编译的时候才能找到**xsd__date = #import "custom/struct_tm_date.h" | xsd__date** 中指定的$gsoap/gsoap/custom/struct_tm_date.h文件

$gsoap/gsoap/custom/struct_tm_date.c复制到你的项目代码目录下,并添加到工程文件中。
这里写图片描述
注意:
如果你生成的是c++代码,那么这个文件的后缀要改为cpp,否则会因为与#include 头文件中的c++定义冲突而无法编译

如果你在执行soapcpp2时使用了-p<prefix>参数,那么请打开struct_tm_date.cpp,如下图将#include <soapH.h>修改为#include <<prefix>H.h>
这里写图片描述

如果你的webservice处理xsd:date类型时没有时区(ZONE)信息,那么要在struct_tm_date.cpp编译选项中加入预处理器宏定义WITH_NOZONE(/D "WITH_NOZONE"),否则会因无法解析xsd:date类型的字符串而在运行时报错。
参见《9.11 Library Build Flags》
这里写图片描述
然后你就可以正常编译并使用gsoap的webservcie调用啦!

包含时间的xsd:date

按照schema标准,xsd:date类型的数据只包含日期,没有时间。如果你的webservice服务器进行了定制改装,xsd:date类型是包含完整的日期时间信息的("yyyy-MM-dd’T’HH:mm:ss.SSSZ),(参见我的另一篇博客《解决axis2处理java.util.Date类型对象时丢弃时间部分的问题》),那么gsoap用struct_tm_date.c解析xsd:date类型的数据返回的struct tm结构中没有时间部分的信息。
解决这个问题的办法是struct_tm.c来代替struct_tm_date.c
将typemap.dat中的类型映射从

xsd__date = #import "custom/struct_tm_date.h" | xsd__date

改为

xsd__date = #import "custom/struct_tm.h" | xsd__dateTime

然后其他步骤如前一样如法炮制就可以了。
这里写图片描述

参考资料:
《XSD 日期及时间数据类型(Date and Time Data Types)》http://www.w3school.com.cn/schema/schema_dtypes_date.asp

在 ONVIF 的代码生成过程中,**XSD(XML Schema Definition)文件** 扮演着关键角色,它们定义了 WSDL 中使用的数据结构、数据类型和消息格式。以下是 XSD 文件的作用及在 gSOAP 生成代码时的具体用法: --- ### **1. XSD 文件的核心作用** #### **(1) 定义数据类型和结构** - XSD 文件规定了 SOAP 消息中使用的 **XML 数据结构**,例如: - `common.xsd`:定义 ONVIF 的公共类型(如 `DNSInformation`、`IPAddress`)。 - `types.xsd`:定义核心数据类型(如 `Capabilities`、`PTZConfiguration`)。 - 这些定义会被转换为 C/C++ 的 **结构体/类**(如 `_tds__GetCapabilitiesResponse`)。 #### **(2) 约束数据格式** - 指定字段的 **数据类型**(如 `xs:string`、`xs:int`)、**可选性**(`minOccurs="0"`)和 **取值范围**。 - 例如:`DeviceServiceCapabilities` 中的字段是否可为空。 #### **(3) 支持 WSDL 的完整性** - WSDL 文件依赖 XSD 来定义 **消息体** 和 **端口类型**。例如: ```xml <!-- 在 WSDL 中引用 XSD --> <types> <xsd:schema targetNamespace="..."> <xsd:import namespace="http://www.onvif.org/ver10/schema" schemaLocation="common.xsd"/> </xsd:schema> </types> ``` --- ### **2. 在 gSOAP 生成代码时如何使用 XSD** #### **(1) 直接通过 WSDL 隐式引用** 大多数情况下,WSDL 文件已通过 `<xsd:import>` 关联了 XSD 文件。生成代码时,`wsdl2h` 会自动下载或查找本地 XSD: ```bash wsdl2h -o onvif.h http://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl ``` - **自动处理依赖**:`wsdl2h` 会解析 WSDL 中的 `<xsd:import>`,并递归加载所有关联的 XSD。 #### **(2) 手动指定本地 XSD 路径** 如果 XSD 文件在本地(如离线环境),需通过 `-d` 指定搜索路径: ```bash wsdl2h -o onvif.h -d ./xsd_files/ devicemgmt.wsdl ``` - 确保 XSD 文件与 WSDL 中的 `schemaLocation` 路径一致。 #### **(3) 解决 XSD 加载失败问题** 若遇到错误(如 `Unable to locate schema file`): 1. **检查 XSD 文件是否存在**: ```bash find . -name "*.xsd" # 确认本地是否有需要的 XSD ``` 2. **手动下载缺失的 XSD**: - 从 ONVIF 官网或设备厂商获取 XSD,保存到 `-d` 指定的目录。 3. **强制忽略缺失的 XSD**(不推荐): ```bash wsdl2h -o onvif.h -ignore-import devicemgmt.wsdl ``` --- ### **3. 生成代码中的 XSD 体现** 通过 `wsdl2h` 和 `soapcpp2` 生成的代码会反映 XSD 的定义: #### **(1) 数据类型映射** - XSD 的复杂类型 → C/C++ 结构体 ```xml <!-- XSD 定义 --> <xs:complexType name="NetworkInterface"> <xs:sequence> <xs:element name="Enabled" type="xs:boolean"/> <xs:element name="MTU" type="xs:int"/> </xs:sequence> </xs:complexType> ``` ```cpp // 生成的 C++ 代码 class ns1__NetworkInterface { bool Enabled; int MTU; }; ``` #### **(2) 命名空间处理** - XSD 的 `targetNamespace` → 生成代码中的命名空间 ```xml <!-- XSD 文件 --> <xs:schema targetNamespace="http://www.onvif.org/ver10/schema"> ``` ```cpp // 生成的头文件 namespace ns1 { class NetworkInterface { ... }; // ns1 对应 ONVIF 的命名空间 } ``` #### **(3) 数据校验逻辑** - XSD 的约束条件(如 `minOccurs="1"`)→ 生成代码中的 **非空检查**。 --- ### **4. 关键注意事项** 1. **XSD 版本匹配** - 确保 WSDL 和 XSD 来自同一 ONVIF 版本(如 `ver10` vs `ver20`),否则会因字段不匹配导致生成失败。 2. **自定义类型扩展** - 如需扩展 ONVIF 类型,可修改本地 XSD 文件后重新生成代码(但需注意兼容性)。 3. **二进制数据(如 `xs:base64Binary`)** - gSOAP 会将其转换为 `struct xsd__base64Binary`,需手动处理内存分配。 --- ### **5. 示例:完整生成流程** ```bash # 1. 下载 WSDL 和 XSD 到本地 wget http://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl wget http://www.onvif.org/ver10/schema/common.xsd # 2. 生成头文件(自动关联 XSD) wsdl2h -o onvif.h -d ./ devicemgmt.wsdl # 3. 生成 C++ 代码 soapcpp2 -j -CL -x -I/usr/share/gsoap/import onvif.h # 4. 编译 g++ -o client soapClient.cpp soapC.cpp main.cpp -lgsoap++ ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值