gSOAP - 将XML数据转换为C结构体(由gSOAP自动生成)

4
我有关于使用gSOAP解析XML的问题。 如果有人有相关经验,请给我提供一些帮助。谢谢:D
我以前不了解XML,现在需要将XML解析到C中的结构体中。然后我找到了一些建议使用gSOAP数据绑定的方法。没错!它帮助我生成了一个包含从XSD(XML模式)中的结构体的头文件。但是现在,我不知道该对结构体或XML文件做什么。我需要自动将XML数据放入结构体中(我的意思是,如果XSD更改,则代码不应该被更改)。与我的问题相关的gSOAP是否有任何我不知道的东西?还是我必须自己编写代码来放置数据?感谢您的关注和时间。
干杯!
----补充----
这是我所做的,在Linux的终端中工作: 我有一个名为try.xsd的XSD文件。
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name='Root'>
        <xs:complexType>
        <xs:sequence>
            <xs:element name='Customers'>
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name='Customer' type='xs:string' minOccurs='0' maxOccurs='unbounded' />
                        <xs:element name='Order' type='xs:string' minOccurs='0' maxOccurs='unbounded' />
                    </xs:sequence>
                    <xs:attribute name='customerid' use='required' type='xs:integer'/>
                </xs:complexType>
        </xs:element>
        </xs:sequence>
    </xs:complexType>
</xs:element>
</xs:schema>

然后我使用这个XSD文件和gSOAP:
通过wsdl2h生成了try.h文件:
wsdl2h -c -a -o try.h -t typemap.dat try.xsd
接着,我通过以下命令生成其他文件:ns1.nsmap, soapC.c soapH.H soapClient.c soapServer.c soapStub.h:
soapcpp2 -c -t -L -I "/home/celia/Documents/gsoap-2.7/gsoap/import" try.h
然后生成了.c文件,并包含了soapH.h和ns1.nsmap。同时在你的文件夹中包含stdsoap2.h和stdsoap2.c(可以在gSOAP软件包中找到)。
在soapStub.h文件中,结构体被构建:
....
struct _ns1__Root_Customers
{
    int __sizeCustomer;     /* sequence of elements <Customer> */
    char **Customer;        /* optional element of type xsd:string */
    int __sizeOrder;        /* sequence of elements <Order> */
    char **Order;               /* optional element of type xsd:string */
    char *customerid;       /* required attribute of type xsd:integer */
}

struct _ns1__Root
{
    struct _ns1__Root_Customers Customers;        /* required element of type ssrf1:Akar-Customers */
}
....

所以现在,我不知道如何编码使XML数据自动进入这个结构,而不需要手动输入“Customers->customerid = node->children->content”。因此,如果XSD更改,我也不必更改代码。

2个回答

0

使用gSOAP和字符串流填充结构体,您可以在C++中执行以下操作:

struct _ns1__Root_Customers customers;
struct soap *ctx = soap_new();
istringstream in;
in.str("<in><Customer>a</Customer><Order>b</Order><customerid>123</customerid></in>");
ctx->is = in;
soap_read__ns1__Root_Customers(ctx, &customers);
soap_free(ctx); // does not dealloc 'customers' data (soap_end(ctx) before soap_free() will)

在C语言中,你可以使用FILE* fd来设置要读取的源文件ctx->recvfd = fd。有一个技巧可以从C字符串中读取数据,它涉及重新定义::frecv()回调函数以从该字符串中读取并将内容复制到引擎读取的内部缓冲区。这需要一些额外的工作来重新定义回调函数。
编辑:为了回答你问题的第二部分,有一种方法可以声明结构体成员的任意名称,这是一个文档稀缺的特性。
struct _ns1__Root_Customers
{ …
  char *whateveryouwant `customerid`;

成员名称后面的是合格或不合格的 XML 标记名称(请谨慎使用)。


啊,实际上,这要求我永远不会自己编写元素的名称,因此如果我更改XSD(包括元素的名称和属性的名称),我就不必更改代码。但是要访问结构成员,我应该知道成员名称。所以,仍然需要手动编写名称。 - user2809943

0
在 C 语言中没有像 C++ 或 C# 那样的序列化 / 反序列化对象,其中有填充结构体的类。 你必须自己编写代码,并使用 "read" 和 "memcpy" 函数进行帮助。 这就是我所做的,我曾经遇到过同样的问题,但现在可能有一些新的东西我不知道。

非常感谢提供的信息!我通常使用C++而不是C。那么它可以自动化吗?我的意思是,如果我有一个结构体idInfo { int id };,我能否自动将<id>5</id>放入结构体中? 你如何检测结构体中的名称"id"与XML元素中的名称"id"是否相同?如果我问得太多了,请原谅。这个问题最近确实困扰着我。谢谢! - user2809943
变得自动化,你的意思是编写一个在C中可以接受空结构体和XML文件名作为参数的序列化对象代码。我不知道如何在C代码中获取变量名。 - Gabson
嗯...将XML元素名称设置为结构体成员是由gSOAP完成的,但将特定元素的值放入与元素名称相同的结构体成员中实际上是问题所在。 - user2809943

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接