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.
Examples
--------
Examples are provided in the software package, using a C and C++ interface:
xml-rpc-currentTime.c client in C
xml-rpc-currentTime.cpp client in C++, also uses JSON to display time
xml-rpc-currentTimeServer.cpp server in C++
xml-rpc-weblogs.c client 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 St
评论8
最新资源