Value Manipulations

Value Types

The following table shows the mapping between standard XML-RPC types and the corresponding library classes that should be used for their creation. Namespace prefix iqxmlrpc omitted.

XML-RPC Libiqxmlrpc
boolean Value
i4 Value
double Value
string Value
date/time Date_time
base64 Binary_data
array Array
struct Struct
nil Nil

The Value class should not be used directly for all XML-RPC types. As you can see, it should be used to construct most scalars (i.e. atomic values). However, exceptions include: date/time and base64 types; and complex types such as arrays and structs. These should be constructed by using their distinct classes.

However, the actual values are always stored in the Value class, eventually. Although it is the library's central entity responsible for value manipulation, there are helper classes that manipulate non-trivial value types, such as Binary_data or Array.

Value Container

There is a super-container class called iqxmlrpc::Value that may hold values of any type described in the XML-RPC standard. It tries to provide the power of variables found in dynamic languages, i.e. anyone can change their type by assigning a new value, but strict type-checking prevents their type from being misinterpreted.

Value objects can be directly assigned to with scalars:

Value v = 10;
v = "Hello";
v = 1.05;
v = false;

It is also possible use Value objects where C++ native types are required, as the class contains type casting operators for most scalar types:

void foo(const std::string&);
void bar(int);
 
Value v1 = "test";
Value v2 = 100;
foo(v1);
bar(v2);
 
// ambiguity: use get_xxx methods
std::cout << v1.get_string();
std::cout << v2.get_int();

Misinterpreting the type of a Value object will cause a Value::Bad_cast exception to be thrown. If in doubt, check if the object has the type you are interested in:

if ( not v1.is_int() ) {
    // ...
}

Arrays

Arrays are constructed as an instance of the iqxmlrpc::Array class. The Array::push_back method should be used for appending new tail elements. The [] operator (square braces) provides access to array elements in the usual way.

Array a;
a.push_back(1);
a.push_back(0.5);
a.push_back(Array());
 
assert( a.size() == 3 );
assert( a[0] == 0.5 );
assert( a[2].is_array() );

Array objects may also be assigned to Value.

Value v = Array();
v.push_back( 10 );
 
assert( v.is_array() );
assert( v.size() == 1 );
assert( v[0] == 10 );
assert( *v.arr_begin() == 10 );

Furthermore, values have methods that partially cover the interface of the Array class itself, so arrays can be operated using a Value object too. The Value::the_array method provides reference to an embedded Array object.

Array Iterators

Array objects have iterators that are compatible with STL ones. There is also an assign method that allows sequences to be easily converted into XML-RPC arrays.

void f(const std::vector<int>& vi)
{
    Array a;
    a.assign(vi.begin(), vi.end());
 
    unsigned vidx = 0;
    for (Array::const_iterator i = a.begin(); i != a.end(); ++i) {
        assert( i->get_int() == vi[vidx++] );
    }
}
 
Value gen();
 
void g(Array& a, unsigned n)
{
    std::generate_n(std::back_inserter(a), n, g);
}

Structs

In Libiqxmlrpc, structures are constructed by creating an instance of the iqxmlrpc::Struct class. These are an essential part of nearly all XML-RPC communications, because they allow meanings to be assigned to particular elements. Structures are actually maps between string types and any of the XML-RPC value types.

The insert method should be used for inserting a new mapping into a struct. Whereas, the [] operator (square braces) enables existing elements of structures to be accessed. The [] operator for iqxmlrpc::Struct does not insert non-existent elements, but throws a Struct::No_field exception, unlike std::map. So check for an element's presence with the has_field method, if unsure.

Struct s;
s.insert("title", "Eternal Sunshine of The Spotless Mind");
s.insert("imdb_no", "tt0338013");
s.insert("issued", 2004);
 
assert( s["issued"] == 2004 );
assert( s.has_field("title") );

A Struct instance can be assigned to a Value one, as is the case with the Array class. This is because Value is the only type to be used when composing and parsing XML-RPC packets. The Value class also allows some manipulation of embedded structures, in line with the Array class.

Value v = Struct();
 
assert( v.is_struct() );
 
v.insert("field", Array());
v["field"].push_back(0);

Binary Data

The iqxmlrpc::Binary_data class enables binary data to be sent / received by transferring it through the network in BASE64 form. An instance of this class can be constructed from raw data as well as from encoded text.

std::string raw = "Hello, World!";
 
std::auto_ptr<Binary_data> b( Binary_data::from_data(raw) );
std::string enc = b->get_base64();
 
assert( enc == "SGVsbG8sIFdvcmxkIQ==" );
 
b.reset( Binary_data::from_base64(enc) );
 
assert( b->get_data() == raw );

A Binary_data instance can be also constructed from a byte sequence, rather than std::string.

Binary_data*
void encode(const char* buf, size_t size)
{
    return Binary_data::from_data(buf, size);
}

Date / Time

XML-RPC date/time types are accessed and manipulated through the iqxmlrpc::Date_time class. This transfers payload values in ISO 8601 time format. The date/time strings must strictly be in the 17 character YYYYMMDDTHH:MM:SS format, with no timezone information.

An instance of the Date_time class can be constructed in one of three ways:

// Using struct tm
// Date_time(const struct tm*)
time_t t = time(NULL);
Date_time dt(gmtime(&t));
Date_time dt(localtime(&t));
 
// Using an ISO 8601 formatted string
// Date_time(const std::string&)
Date_time dt("19980717T14:08:55");
 
// Allowing the class itself to fetch the time
// Date_time(bool localtime).
Date_time dt(true);
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License