XMLRPC value types and C++

A while ago, I was looking for a C/C++ XMLRPC client implementation. However, for some reason or another, I was unsatisfied with the recent implementations, which mostly seem utterly complex for my purposes. That’s why I decided to roll out my own. While the XML building and parsing is more or less straight forward (although there’s too much redundancy and unneccessary tags in the spec for my taste), implementing the possible value types made me scratch my head. The XMLRPC protocol supports a set of data types: integer, string, double etc., but also an array or a struct. Integer and double are native types, string is either a char pointer or a class. How this should be put within one class? My first sketch introduced a quite complex model with an impressing inheritence chain, but then boost::variant came to the rescue:

/*! \brief XmlRpcValue is defined as a variant that can
 *         take string, int, double, bool,
 *         and collections of itself, namely a vector and a map
 */
typedef boost::make_recursive_variant<
    std::string,
    int,
    bool,
    double,
    std::map< std::string, boost::recursive_variant_ >,
    std::vector< boost::recursive_variant_ >
>::type XmlRpcValue;

/*! \brief Key and value pairs form a struct
 */
typedef std::map< std::string, XmlRpcValue > XmlRpcStruct;

/*! \brief A list forms an array 
 */
typedef std::vector< XmlRpcValue > XmlRpcArray;

This defines a type called XmlRpcValue. This type can contain either a string, an int, a bool, a double, or a vector of XmlRpcValues or a string-based map of XmlRpcValues. Isn’t that cool?

We can easily utilize this type like this:

/*! \brief convert given parser value into xmlrpc value.
 *
 * \exception boost::lecial_cast_error
 *              Conversion wasn't successful
 * \exception std::invalid-argument
 *              Data type not recognized
 */
static XmlRpcValue _read_parser_value(const ParserValue& val) throw (std::exception) {
    // Check all types
    if (val->type == "int" || val->type == "i4") {
        return XmlRpcValue(boost::lexical_cast<int>(val->value));
    }
    if (val->type == "double") {
        return XmlRpcValue(boost::lexical_cast<double>(val->value));
    }
    [...]
    // Unrecognized data type
    throw std::invalid_argument("Unknown data type detected");
}

ParserValue in this case is a simple structure containing information about parsed data:

/*! \brief A single value extracted from response
 */
struct ParsedValue {
public:
    /*! \brief The name. Used only for struct members */
    std::string name;
    /*! \brief The value as string */
    std::string value;
    /*! \brief The type, value type tag name like
     *         "int", "struct", "array" etc. */
    std::string type;
};

Published: August 05 2006