GSOAP

gSOAP is a C and C++ software development toolkit for SOAP/XML web services and generic XML data bindings. Given a set of C/C++ type declarations, the compiler-based gSOAP tools generate serialization routines in source code for efficient XML serialization of the specified C and C++ data structures. Serialization takes zero-copy overhead.
History.
The gSOAP toolkit started as a research project at the Florida State University by professor Robert van Engelen in 1999. The project introduced new methods for highly-efficient XML parsing (pull parsing) and serialization of C/C++ data directly in XML and later also in SOAP. The project succeeded at defining type-safe data bindings between XML schema types and a wide variety of C/C++ data types. The toolkit uses automatic programming to simplify the development and invocation of Web services using efficient auto-generated XML serializers to send and receive C/C++ data directly. A domain-specific compiler-based tool generates source code that efficiently converts native C/C++ data structures to XML and back. The toolkit was further developed to support the SOAP web services messaging protocol, introduced at around the same time, therefore the name "gSOAP" (generic XML and SOAP) and to use the approach for scientific data exchange. Further development and maintenance of the software took place under ownership of Genivia Inc. This includes the addition of new WSDL and XML schema processing capabilities as well as the addition of many WS-* web services protocol capabilities such as WS-Security optimizations, XML-RPC messaging, support for the JSON data format, plugin modules to integrate gSOAP in Apache and IIS web servers, and third-party plugins such as for Grid Services. The gSOAP toolkit is written in portable C/C++ and uses a form of bootstrapping by generating its own code to implement a converter to translate WSDL/XSD specifications to C/C++ source code for WSDL/XSD meta-data bindings. The gSOAP software is licensed under the GPLv2 open source license and commercial-use source code licenses. The gSOAP software is widely used in industrial projects and mission-critical infrastructures.
XML Web Service Operations by Example.
An example web service operation in C for retrieving the lodging rate of a hotel given a number of guests can be declared in annotated form as
//gsoap ns service namespace: tempuri
//gsoap ns service style: document
//gsoap ns service encoding: literal
int ns__get_rate(char* hotel, int guests, float *rate);
The last parameter of the function is always the service return value, which can be denoted as void for one-way operations and should be a struct/class to bundle multiple service return parameters. The function's int return value is used for error diagnostics.
A service invocation in C using the auto-generated soap_call_ns__get_rate function is executed as follows:
const char *URL = "http://www.example.com/hotels";
const char *action = NULL;
struct soap *ctx = soap_new(); // new context
float rate;
int err = soap_call_ns__get_rate(ctx, URL, action, "Happy Inn", 2, &rate);
if (err == SOAP_OK && rate < 100.00)
 lets_go();
soap_end(ctx); // deallocate deserialized data
soap_free(ctx); // deallocate context
To facilitate web services implementations for legacy C and C++ systems, the prefix qualification of identifier names in C/C++ can be omitted or can be replaced by colon notation, for example ns:get_rate rather than ns__get_rate. The punctuation is removed in the auto-generated source code that is used in project builds.
A service invocation in C++ using the auto-generated Proxy class is executed as follows (using the Proxy's default endpoint URL and SOAP action values):
Proxy proxy;
float rate;
int err = proxy.get_rate("Happy Inn", 2, &rate);
if (err == SOAP_OK && rate < 100.00)
 lets_go();
proxy.destroy(); // deallocate deserialized data
By using annotations and identifier naming conventions, i.e. qualification with the prefix ns__ for the function ns__get_rate and by declaring properties of the ns namespace using the //gsoap directives in the example, a binding is established to web service operations. The auto-generated Web Services Description Language (WSDL) document declares a request message, a response message, and the get-rate operation portType interface and SOAP binding for the ns__get_rate function as follows:
<definitions name="Service" targetNamespace="tempuri" xmlns:tns="tempuri" xmlns:ns="tempuri"
 xmlns="http://schemas.xmlsoap.org/wsdl/">
<message name="get-rateRequest">
 <part name="parameters" element="ns:get-rate"/>
</message>
<message name="get-rateResponse">
 <part name="parameters" element="ns:get-rateResponse"/>
</message>
<portType name="ServicePortType">
 <operation name="get-rate">
 <input message="tns:get-rateRequest"/>
 <output message="tns:get-rateResponse"/>
 </operation>
</portType>
<binding name="Service" type="tns:ServicePortType">
 <SOAP:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
 <operation name="get-rate">
 <SOAP:operation soapAction=""/>
 <input>
 <SOAP:body parts="parameters" use="literal"/>
 </input>
 <output>
 <SOAP:body parts="parameters" use="literal"/>
 </output>
 </operation>
</binding>
where the request and responses messages of the operation refer to XML elements that are defined in the types section of the WSDL as follows:
<types>
 <schema targetNamespace="tempuri" ...> 
 <element name="get-rate">
 <complexType>
 <sequence>
 <element name="hotel" type="xsd:string" minOccurs="0" maxOccurs="1" nillable="true"/>
 <element name="guests" type="xsd:int" minOccurs="1" maxOccurs="1"/>
 </sequence>
 </complexType>
 </element>
 <element name="get-rateResponse">
 <complexType>
 <sequence>
 <element name="rate" type="xsd:float" minOccurs="0" maxOccurs="1" nillable="true"/>
 </sequence>
 </complexType>
 </element>
 </schema>
</types>
Likewise, client and server C/C++ source code can be auto-generated from a set of WSDLs and XML schemas. Services must be completed by defining the appropriate service operations. For example, the auto-generated C++ service class for this WSDL must be completed by defining the get_rate method as follows:
int Service::get_rate(char *hotel, int guests, float *rate)
 *rate = ... // determine the lodging rate of the hotel given the number of guests
 return SOAP_OK;
There are no restrictions on the type of the operation parameters that can be marshaled in XML for web service messaging, except that certain type declaration conventions and annotations should be followed to establish a data binding.
XML Data Binding by Example.
To establish an XML data binding with C/C++ data types, gSOAP uses three basic forms of source code annotation: directives, identifier naming conventions, and punctuation.
A fully annotated structure declaration in C for a hierarchical employee record may appear as
//gsoap ns schema namespace: tempuri
//gsoap ns schema form: qualified
struct ns__employee_record
 @char *xml__lang = "en";
 @int ID = 9999;
 char *full_name 1:1; 
 $int size 0:12;
 struct ns__employee_record *manages;
where the following annotations and conventions are used:
The gSOAP tools convert C/C++ data types to/from XML schema data types. Since C does not support namespaces and struct/class member names cannot be namespace-qualified in C++, the use of identifier naming conventions in gSOAP allow for binding this structure and its members to an XML schema complexType that is auto-generated as follows:
<schema targetNamespace="tempuri" xmlns:ns="tempuri"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3.org/2001/XMLSchema"
 elementFormDefault="qualified" attributeFormDefault="qualified">
 <complexType name="employee-record">
 <sequence>
 <element name="full-name" type="xsd:string" minOccurs="1" maxOccurs="1" nillable="true"/>
 <element name="manages" type="ns:employee-record" minOccurs="0" maxOccurs="12"/>
 </sequence>
 <attribute ref="xml:lang" use="default" default="en"/>
 <attribute name="ID" type="xsd:int" use="default" default="9999"/>
 </complexType>
</schema>
Furthermore, unions in a struct/class that are annotated with a special selector field for union member selection are mapped to/from schema choice particles, STL containers are mapped to/from sequence particles, enumerations are mapped to/from XML schema simpleType enumerations, and standard C/C++ primitive types are mapped to/from XSD types. For conversion of XSD schema to C/C++ data types, the actual mapping is configurable in gSOAP with a type mapping file.
An instance of the example hierarchical employee structure is serialized in XML as a tree by default, for example
<ns:employee xmlns:ns="tempuri" xml:lang="en" ns:ID="12">
 <ns:full-name>Jane Doe</ns:full-name>
 <ns:manages xml:lang="en" ns:ID="34">
 <ns:full-name>John Doe</ns:full-name>
 </ns:manages>
 <ns:manages xml:lang="en" ns:ID="56">
 <ns:full-name>Bob Oz</ns:full-name>
 <ns:manages xml:lang="en" ns:ID="78">
 <ns:full-name>Alice Oz</ns:full-name>
 </ns:manages>
 </ns:manages>
</ns:employee>
When the SOAP encoding style is enabled, the XML serialization in gSOAP respects co-referenced objects and cyclic data structures as per SOAP encoding rules resulting in XML with "id-ref" edges.
The auto-generated XML data binding includes read and write operations to/from a file, string or stream. For example, an ns__employee_record object has read and write operations:
int soap_read_ns__employee_record(struct soap*, ns__employee_record*);
int soap_write_ns__employee_record(struct soap*, const ns__employee_record*);
To read an employee record from an XML file:
struct soap *ctx = soap_new();
ctx->recvfd = open("employee.xml", O_RDONLY);
if (ctx->recvfd)
 ns__employee_record employee;
 if (soap_read_ns__employee_record(ctx, &employee) == SOAP_OK)
 close(ctx->recvfd);
soap_end(ctx);
soap_destroy(ctx); // also deletes employee data
soap_free(ctx);
Parsed XML is internally validated against the data bindings' constraints.
XML REST API.
Application data can be sent and received to/from a REST XML service. The XML data binding provides REST XML API calls. For example, given the ns__employee_record XML data binding of the previous section, the following GET, PUT and POST operations are auto-generated:
int soap_GET_ns__employee_record(struct soap*, const char *URL, ns__employee_record*);
int soap_PUT_ns__employee_record(struct soap*, const char *URL, const ns__employee_record*);
int soap_POST_send_ns__employee_record(struct soap*, const char *URL, const ns__employee_record*);
int soap_POST_recv_ns__employee_record(struct soap*, ns__employee_record*);
The POST functions should be called together, first a POST_send to transmit XML data to the endpoint URL followed by a POST_recv to accept the response data (may be of a different type).
Received XML is internally validated against the data bindings' constraints.