4

I have some questions about using gSOAP for parsing the XML. If anyone has been experienced with this, please give me some helps. Thanks :D

I never know about XML before, and now I need to parse the XML to the structs in C. Then I found some recommendation to use gSOAP data binding. And yes! it helps me to generate a header file contains of structs from an XSD (XML Schema). But now, I don't know what to do with the struct or the XML file either. I need to put the XML data into the struct automatically (I mean, if the XSD change, the code shouldn't have to be changed also). Is there anything I don't know about gSOAP related to my problem? Or I have to code myself to put in the data? Thank you for your concern and time.

Cheers!

----Addition----

This is what I have done, I worked in Terminal in Linux : I have an XSD file named try.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>

Then I use gSOAP with this XSD file :

I generated the try.h file with the wsdl2h by

wsdl2h -c -a -o try.h -t typemap.dat try.xsd

Then I generated the rest files : ns1.nsmap, soapC.c soapH.H soapClient.c soapServer.c soapStub.h by

soapcpp2 -c -t -L -I "/home/celia/Documents/gsoap-2.7/gsoap/import" try.h

Then make the .c file and included the soapH.h and ns1.nsmap. Also include in your folder the stdsoap2.h and stdsoap2.c (you can find them in the gSOAP package).

In the file soapStub.h, the struct is built :

....
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 */
}
....

So now, I'm confused how to code that make the XML data automatically go to this struct without manually "Customers->customerid = node->children->content". So, if the XSD change, I don't have to change the code also.

user2809943
  • 61
  • 3
  • 6

2 Answers2

0

In C there is no serialization / deserialization object ( not like in C++ or c# ) where there are class that fill the struct. You have to code it yourself, with the helps of "read" and "memcpy" functions. Thats what i have done, i had the same problem but now maybe there is something new that i don"t know.

Gabson
  • 421
  • 1
  • 4
  • 20
  • Thanks a lot for the information! I always work with C++ instead of C. And could it become automatic? I mean if I have struct idInfo { int id }; Can I automatically put in 5 to the struct? How can you detect the name "id" from the struct is the same with the name "id" from XML element. Sorry if I ask a lot. This problem really disturb me recently. Thanks! – user2809943 Oct 24 '13 at 12:25
  • Become automatic, you mean code a serialization object in C wich could take an empty strutc and the xml file name in parameters. I don't know how to know a variable name in code in C. – Gabson Oct 24 '13 at 12:28
  • Hmm... about making the XML elements name as the struct's members is done by gSOAP, but to put in the value of the particular element to the struct's member that has the same name with the element's name is actually the problem. – user2809943 Oct 25 '13 at 07:20
0

You can do the following in C++ with gSOAP, by using string streams to populate structs:

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)

In C you can use a FILE* fd to set the source to read from ctx->recvfd = fd. There is a trick to read data from C strings that involves redefining the ::frecv() callback to read from this string and copy to content to the internal buffer that the engine reads from. That requires a bit more work to redefine the callback.

Edit: to answer your second part of the question, there is a way to declare the struct members with any name you want, which is a feature that is sparsely documented:

struct _ns1__Root_Customers
{ …
  char *whateveryouwant `customerid`;

where after the member name is a qualified or unqualified XML tag name (use with care).

Dr. Alex RE
  • 1,772
  • 1
  • 15
  • 23
  • ah, actually, it requires that I will never write the element's name by myself, so if I change the XSD (include the element's name and attribute's name), I don't have to change the code. But to access the struct member, I should know the member name. So, still, I need to write manually the name. – user2809943 Oct 30 '13 at 13:22