gSOAP 数据操作
转自:https://github.com/stoneyrh/gSOAP/tree/master/gsoap/samples/xml-rpc-json
XML-RPC Support with Optional JSON Serialization ================================================ XML-RPC is a simple and effective messaging protocol. XML-RPC uses a generic XML format to compose messages. XML serialization proceeds by marshaling parameters in predefined XML elements. A simple type system is provided to cover primitive types, structs, and arrays. That is, XML-RPC defines a couple of frequently used XML types with common programming language equivalents. XML-RPC does NOT provide a data binding to XML and does NOT implement a validation mechanism to ensure that XML content is valid. See http://www.xmlrpc.com for more details. JSON (JavaScript Object Notation) is an even simpler data format that is highly compatible across programming languages. See http://www.json.org for more details. C++ API for XML-RPC with JSON Support ------------------------------------- The following source files are provided for XML-RPC support in C++: xml-rpc.h XML-RPC bindings (gSOAP specification file for soapcpp2) xml-rpc.cpp C++ XML-RPC API xml-rpc-io.h C++ XML-RPC data serialization over streams xml-rpc-io.cpp C++ XML-RPC data serialization over streams xml-rpc-iters.cpp C++ iterators for structs, arrays, and parameters For JSON serialization, use the following files instead of xml-rpc-io.h and xml-rpc-io.cpp: json.h C++ JSON serializer over streams json.cpp C++ JSON serializer over streams For JSON over HTTP (JSON REST method), please use the plugin/httppost.c plugin. See JSON over HTTP explanation below. Note that soapH.h, soapStub.h and soapC.cpp are required for XML-RPC and JSON. To create these execute: > soapcpp2 -CSL xml-rpc.h Also compile and link with stdsoap2.cpp (or libgsoap++.a installed by the package). C++ Examples ------------ Examples are provided in the software package: xml-rpc-currentTime.cpp client in C++, also uses JSON to display time xml-rpc-currentTimeServer.cpp server in C++ xml-rpc-weblogs.cpp client in C++ xml-rpc-json.cpp XML-RPC <=> JSON serialization example See xml-rpc.h for the C++ member functions to create XML-RPC messages and decode responses. These functions are intuitive casts, assignments, and indexing functions. An XML-RPC data value is created in C++ as follows, which requires a context (ctx) for the engine state (stored in the soap struct) for communication, memory management, and data allocation/deallocation: struct soap *ctx = soap_new(); value v(ctx); This creates an empty value. It can be assigned using any one of the following: v = 12345; // an int v = 12.34; // a double v = "abc"; // a string v = false; // a Boolean v = time(0); // a time_t value, serialized as XML-RPC dateTime element v[0] = 24; // an array [24,99] v[1] = 99; v["name"] = "john"; // a struct {"name": "john", "age": 24} v["age"] = 24; _base64 img(ctx, 100, rawimage100bytes); v = img; // a data block of 100 bytes (bas64) You can combine this syntax to create arrays of structs etc: v[0]["name"] = "john"; // first array element is a struct with member "name" To check the type of a value in C++, use: v.is_int() v.is_double() v.is_string() v.is_bool() v.is_true() v.is_false() v.is_dateTime() v.is_array() v.is_struct() v.is_base64() And two array value methods: v.size(int) // (re)set array size (pre-allocates) v.size() // size of the array, if v is an array (0 otherwise) To extract a value use casts or array/struct indexing: (int)v; (double)v; (char*)v (bool)v (time_t)v (_base64)v v[0] v["name"] where _base64::ptr() points to the data of _base64::size() bytes. Iterators can be used to traverse array, struct, and parameter content: param p; ... // populate p for (param::iterator i = p.begin(); i != p.end(); ++i) cout << (*i) << endl; value v; ... // populate v if (v.is_array()) { _array &a = v; for (_array::iterator i = a.begin(); i != a.end(); ++i) cout << (*i) << endl; } else if (v.is_struct()) { _struct &s = v; for (_array::iterator i = s.begin(); i != s.end(); ++i) cout << (*i) << endl; } All dynamically-allocated memory that is internally used to store data is deallocated with: soap_destroy(ctx); // delete objects soap_end(ctx); // free temporary data C++ XML-RCP Client Example -------------------------- A typical XML-RPC calling sequence in C++ is: #include "soapH.h" // generated by the command: soapcpp2 xml-rpc.h ... // create an allocation context soap *ctx = soap_new1(SOAP_C_UTFSTRING); // Store Unicode in UTF8 format // create a call object methodCall mycallobj(ctx, "endpoint URL", "methodXMLTagName"); // create parameter list params input(ctx); // populate parameters input[0] = 123; // first parameter is an integer input[1] = "abc"; // second is a string input[2]["name"] = "joe"; // a record, first member "name" input[2]["age"] = 23; // a record, second member "age" input[3][0] = 456.789; // an array, first element (a float) input[3][1] = "widget"; // an array, second element (a string) input[3][2] = true; // an array, third element (a bool) value record(ctx); // a value (record) record["foo"] = 1; record["bar"] = 2; input[4] = record; // assign record to parameter ... // get array of parameters by making the XML-RPC call params output = mycallobj(input); // check result if (mycallobj.error()) soap_print_fault(ctx, stderr); else if (output.empty()) printf("No response data\n"); else if (output.size() > 1) printf("More than one response data\n"); else if (output[0].is_array() && !((_array)output[0]).empty()) for (int i = 0; i < ((_array)output[0]).size()) ... = output[0][i]; else if (output[0].is_struct()) { ... = output[0]["membername1"]; ... = output[0]["membername2"]; } else if (output[0].is_base64()) _base64 raw = output[0]; else if (output[0].is_bool()) bool flag = output[0]; else if (output[0].is_int()) int num = output[0]; else if (output[0].is_double()) double num = output[0]; else if (output[0].is_string()) const char *str = output[0]; else if (output[0].is_dateTime()) time_t t = output[0]; // deallocate all soap_destroy(ctx); soap_end(ctx); soap_free(ctx); Alternatively, if desired the parameters of the methodCall object can be directly populated as follows: methodCall mycallobj(ctx, "endpoint URL", "methodXMLTagName"); // populate parameters mycallobj[0] = 123; // first parameter is an integer mycallobj[1] = "abc"; // second is a string mycallobj[2]["name"] = "joe"; // a record, first member "name" mycallobj[2]["age"] = 23; // a record, second member "age" mycallobj[3][0] = 456.789; // an array, first element (a float) mycallobj[3][1] = "widget"; // an array, second element (a string) mycallobj[3][2] = true; // an array, third element (a bool) mycallobj[4]["foo"] = 1; mycallobj[4]["bar"] = 2; Note that in the client code, after the response is retrieved, the implicit type casts done by the assignments extracts the values. These casts can be used anywhere to extract values assuming the internal type matches: if (output[0].is_int()) // can we cast to int? std::cout << "int: " << (int)output[0] << std::endl; The above prints the integer value. This works as long as the type is checked first. Casting to string (char*) converts atomic values and base64 data to strings, but not compound types such as arrays and structs. std::cout << "value: " << (char*)output[0] << std::endl; which prints a string representation of the int, double, boolean, time, or base64 value. Nothing is printed for arrays and structs. Use iterators (xml-rpc-iters.h) to walk over arrays and structs to print values. Or use the JSON module to print values in JSON format, see further below. C++ XML-RPC Data Serialization from/to Streams ---------------------------------------------- To send and receive XML over streams, use xml-rpc-io.h and xml-rpc-io.cpp. For example: #include "xml-rpc-io.h" // also compile and link xml-rpc-io.cpp ... std::cout << output[0] << std::endl; which will display the data in XML-RPC format. To parse XML-RPC data from a stream, use: #include "xml-rpc-io.h" // also compile and link xml-rpc-io.cpp ... value input(ctx); std::cin >> input; C++ JSON Serialization from/to Streams -------------------------------------- To display values in JSON format or parse JSON data, use the json.h and json.cpp JSON serializers. It is also possible to send and receive JSON data over HTTP, but this requires some more coding (see JSON over HTTP below). You can dump the XML-RPC data in JSON or populate XML-RPC from JSON data, because the data stored in C++ is independent of XML-RPC and JSON formats. For example: #include "json.h" // also compile and link json.cpp for JSON serialization ... soap *ctx = soap_new(); value input(ctx); std::in >> input; // parse JSON, store as XML-PRC data params output = mycallobj(input); // make the XML-RPC call std::cout << output; // display result in JSON The JSON protocol has fewer data types than XML-RPC, so type information is lost when serializing to JSON. XML-RPC distinguishes ints from floats while JSON does not. XML-RPC also has a dateTime type and a raw binary data type (base64) that JSON lacks. DateTime information is serialized as a string in JSON and binary data is serialized as a base64-formatted string. Unicode is stored in UTF8 format in strings. For compatibility with XML-RPC serialization of UTF8-encoded strings, use the SOAP_C_UTFSTRING flag. C++ JSON over HTTP (REST method) -------------------------------- To serialize JSON over HTTP as a client application, use the plugin/httppost.c: #include "plugin/httppost.h" // also compile and link plugin/httppost.c #include "json.h" // also compile and link json.cpp ... soap *ctx = soap_new(); value request(ctx); // now populate the 'request' data to send ... if (soap_post_connect(ctx, "URL", NULL, "application/json") || json_send(ctx, request) || soap_end_send(ctx)) ... // error value response(ctx); if (soap_begin_recv(ctx) || json_recv(ctx, response) || soap_end_recv(ctx)) ... // error // use the 'response' data response ... // dealloc objects and temp data soap_destroy(ctx); soap_end(ctx); // make other calls etc. ... // dealloc context soap_free(ctx); C++ XML-RPC Server Example -------------------------- A typical C++ XML-RPC server sequence is: // create an allocation context soap *ctx = soap_new(); // create a method object methodCall myobj(ctx); // parse it from stdin, fd, or current socket if (myobj.recv() != SOAP_OK) soap_print_fault(ctx, stderr); else { // create response methodResponse myresponse(ctx); // check method name if (!strcmp(myobj.name(), "methodXMLTagName")) { // method name matches: populate response parameters with values: myresponse[0] = ...; myresponse[1] = ...; ... } else { // otherwise, set fault myresponse.set_fault("Wrong method"); } // send response if (myresponse.send() != SOAP_OK) soap_print_fault(ctx, stderr); } // close (but keep-alive setting keeps socket open) soap_closesock(ctx); // clean up soap_destroy(ctx); soap_end(ctx); // free context (but we can reuse it to serve next call) soap_free(ctx); The server code above uses standard in/out and thus runs over CGI. Use the soap_bind() and soap_accept() calls to bind the server to a port and accept requests via socket, see also the docs and examples for these calls (e.g. samples/webserver.c): // create an allocation context soap *ctx = soap_new1(SOAP_IO_KEEPALIVE); // bind to port 8080 if (!soap_valid_socket(soap_bind(ctx, NULL, 8080))) ... // error, stop // accept messages in server loop for (;;) { if (!soap_valid_socket(soap_accept(ctx))) ... // error, stop // create a method object methodCall myobj(ctx); // parse it from socket if (myobj.recv() != SOAP_OK) soap_print_fault(ctx, stderr); // process request, produce result to send as shown above ... // close (but keep-alive setting keeps socket open) soap_closesock(ctx); // clean up soap_destroy(ctx); soap_end(ctx); } // free context soap_free(ctx); C API for XML-RPC with JSON Support ----------------------------------- The following source files are provided for XML-RPC support in C: xml-rpc.h XML-RPC bindings (gSOAP specification file for soapcpp2) For JSON serialization, use the following files instead of xml-rpc-io.h and xml-rpc-io.cpp: json_c.h C JSON serializer json_c.c C JSON serializer For JSON over HTTP (JSON REST method), please use the plugin/httppost.c plugin. See JSON over HTTP explanation below. Note that soapH.h and soapC.c are required for XML-RPC and JSON. To create these execute: > soapcpp2 -c -CSL xml-rpc.h Also compile and link with stdsoap2.c (or libgsoap.a installed by the package). C Examples ---------- Examples are provided in the software package: xml-rpc-currentTime.c client in C xml-rpc-weblogs.c client in C For C code, only the xml-rpc.h file is needed. To generate the XML-RPC bindings in C, use: soapcpp2 -c xml-rpc.h As a consequence, all message manipulation is done at a very low-level. An XML RPC call is made using the following function you can defined for convenience:: int methodCall(struct soap *soap, const char *URL, struct methodCall *m, struct methodResponse *r) { /* no namespaces */ soap->namespaces = NULL; /* no SOAP encodingStyle */ soap->encodingStyle = NULL; /* connect, send request, and receive response */ if (soap_connect(soap, URL, NULL) || soap_begin_send(soap) || soap_put_methodCall(soap, m, "methodCall", NULL) || soap_end_send(soap) || soap_begin_recv(soap) || !soap_get_methodResponse(soap, r, "methodResponse", NULL) || soap_end_recv(soap)) return soap_closesock(soap); /* closes socket and returns soap->error */ soap_closesock(soap); return SOAP_OK; } Use this XML-RPC method caller in C as follows: struct soap *soap = soap_new1(SOAP_C_UTFSTRING); /* support Unicode */ struct methodCall m; struct methodResponse r; struct param p[4]; /* method has four parameters to send */ int n; /* an int */ double x; /* a float */ struct _struct s; /* a struct ... */ struct member f[2]; /* ... with 2 members */ struct _array a; /* an array ... */ struct value v[2]; /* ... with 2 values */ _boolean False = 0, True = 1; /* Set up method call */ m.methodName = "methodXMLTagName"; /* set the four parameters */ m.params.__size = 4; m.params.param = p; memset(p, 0, sizeof(p)); p[0].value.__type = SOAP_TYPE__string; p[0].value.ref = "a string parameter"; p[1].value.__type = SOAP_TYPE__int; p[1].value.ref = &n; n = 123; p[2].value.__type = SOAP_TYPE__double; p[2].value.ref = &x; x = 4.56; p[3].value.__type = SOAP_TYPE__struct; p[3].value.ref = &s; memset(&s, 0, sizeof(s)); s.__size = 2; s.member = f; memset(f, 0, sizeof(f)); f[0].name = "memberName1"; f[0].value.__type = SOAP_TYPE__boolean; f[0].value.ref = &True; f[1].name = "memberName2"; f[0].value.__type = SOAP_TYPE__array; f[0].value.ref = &a; memset(&a, 0, sizeof(a)); a.data.__size = 2; a.data.value = v; memset(v, 0, sizeof(v)); v[0].__type = SOAP_TYPE__string; v[0].ref = "hello"; v[1].__type = SOAP_TYPE__string; v[1].ref = "world"; /* connect, send request, and receive response */ if (methodCall(soap, "http://domain/path/service", &m, &r)) { soap_print_fault(soap, stderr); exit(soap->error); } if (r.fault) { /* print fault on stdout */ soap_begin_send(soap); soap_put_fault(soap, r.fault, "fault", NULL); soap_end_send(soap); } else { /* print response parameters */ int i; for (i = 0; i < r.params->__size; i++) { printf("Return parameter %d = ", i+1); display(&r.params->param[i].value); /* SEE BELOW */ printf("\n"); } } To dynamically allocate data for automatic deallocation by the gSOAP engine, use (instead of for example struct value v[2]): struct value *v = soap_malloc(soap, 2 * sizeof(struct value)); memset(v, 0, 2 * sizeof(struct value)); ... soap_end(soap); /* deallocate all */ See xml-rpc-currentTime.c and xml-rpc-weblogs.c for example C code. A convenient way to display XML RPC data can be implemented as follows: void display(struct value *v) { int i; switch (v->__type) { case SOAP_TYPE__boolean: printf(*((char*)v->ref) ? "TRUE" : "FALSE"); break; case SOAP_TYPE__double: printf("%g", *((double*)v->ref)); break; case SOAP_TYPE__i4: case SOAP_TYPE__int: printf("%d", *((int*)v->ref)); break; case SOAP_TYPE__dateTime_DOTiso8601: printf("%s", (char*)v->ref); break; case SOAP_TYPE__string: printf("\"%s\"", (char*)v->ref); break; case SOAP_TYPE__base64: printf("[%d bytes of raw data at %p]", ((struct _base64*)v->ref)->__size, ((struct _base64*)v->ref)->__ptr); break; case SOAP_TYPE__struct: printf("{\n"); for (i = 0; i < ((struct _struct*)v->ref)->__size; i++) { printf("\"%s\":", ((struct _struct*)v->ref)->member[i].name); display(&((struct _struct*)v->ref)->member[i].value); printf(",\n"); } printf("}\n"); break; case SOAP_TYPE__array: printf("[\n"); for (i = 0; i < ((struct _array*)v->ref)->data.__size; i++) { display(&((struct _array*)v->ref)->data.value[i]); printf(",\n"); } printf("]\n"); break; default: if (!v->__type) printf("\"%s\"", v->__any); else printf("{?}"); } } C JSON Serialization -------------------- To display values in JSON format or parse JSON data, use the json_c.h and json_c.c JSON serializers. It is also possible to send and receive JSON data over HTTP. You can dump the XML-RPC data in JSON or populate XML-RPC from JSON data, because the data stored in C is independent of XML-RPC and JSON formats. For example: #include "json_c.h" // also compile and link json.cpp for JSON serialization ... struct soap *ctx = soap_new(); struct value v; soap->recvfd = ...; // set file descriptor json_recv(soap, &v); // parse JSON, store as XML-PRC data ... soap->sendfd = ...; // set file descriptor json_send(soap, &v); // output JSON value The JSON protocol has fewer data types than XML-RPC, so type information is lost when serializing to JSON. XML-RPC distinguishes ints from floats while JSON does not. XML-RPC also has a dateTime type and a raw binary data type (base64) that JSON lacks. DateTime information is serialized as a string in JSON and binary data is serialized as a base64-formatted string. Unicode is stored in UTF8 format in strings. For compatibility with XML-RPC serialization of UTF8-encoded strings, use the SOAP_C_UTFSTRING flag. C JSON over HTTP (REST method) ------------------------------ To serialize JSON over HTTP as a client application, use the plugin/httppost.c: #include "plugin/httppost.h" // also compile and link plugin/httppost.c #include "json_c.h" // also compile and link json_c.c ... struct soap *ctx = soap_new(); struct value request; // now populate the 'request' data to send ... if (soap_post_connect(ctx, "URL", NULL, "application/json") || json_send(ctx, request) || soap_end_send(ctx)) ... // error struct value response; if (soap_begin_recv(ctx) || json_recv(ctx, response) || soap_end_recv(ctx)) ... // error // use the 'response' data response ... // dealloc objects and temp data soap_end(ctx); // make other calls etc. ... // dealloc context soap_free(ctx);

浙公网安备 33010602011771号