Search code examples
c++jsonboostboost-propertytree

How can i decide the datatype Boost Property Tree uses?


I am using the Boost Property Tree for a Project and came across a problem. I'm using it like this:

using Namespace boost::property_tree;
ptree proot;

int myInt = 5;

proot.put("Number", myInt);

write_json("myjson.json", proot);

If I use it like this, the data type that is safed is a string, not an int. An example of what i mean:

{ "Number": "5" } //what i get
{ "Number": 5 } //what i want

Is there a way to change that?


Solution

  • No you cannot change this behavior, as the string value type is pretty muched baked into boost::property_tree. While you could technically use different template type parameters than the default ones, you loose much of the conversion logic that went into that library.

    As a somewhat wanky alternative, consider the following.

    #include <boost/property_tree/ptree.hpp>
    #include <boost/property_tree/json_parser.hpp>
    
    using namespace boost::property_tree;
    using boost::property_tree::json_parser::create_escapes;
    
    void writeJsonValue(std::ostream& stream, const ptree& pt)
    {
        const auto raw = pt.get_value<std::string>();
    
        if (raw == "true" || raw == "false") {
            stream << raw;
            return;
        }
    
        if (const auto integral = pt.get_value_optional<int>())
            stream << *integral;
        else
            stream << '"' << create_escapes(raw) << '"';
    }
    

    This essentially reverts some predefined loss of type information. You can use this within an modified version of Boost's json output function:

    void writeJson(std::ostream& stream, const ptree& pt, int indent = 0)
    {
        static const auto indentStr = [](int level) { return std::string(4 * level, ' '); };
    
        if (indent > 0 && pt.empty())
            writeJsonValue(stream, pt);
        else if (indent > 0 && pt.count(std::string()) == pt.size()) {
            stream << "[\n";
    
            for (auto it = pt.begin(); it != pt.end(); ++it) {
                stream << indentStr(indent + 1);
                writeJson(stream, it->second, indent + 1);
                if (boost::next(it) != pt.end())
                    stream << ',';
                stream << '\n';
            }
    
            stream << indentStr(indent) << ']';
        } else {
            stream << "{\n";
    
            for (auto it = pt.begin(); it != pt.end(); ++it) {
                stream << indentStr(indent + 1);
                stream << '"' << create_escapes(it->first) << "\": ";
                writeJson(stream, it->second, indent + 1);
                if (boost::next(it) != pt.end())
                    stream << ',';
                stream << '\n';
            }
    
            stream << indentStr(indent) << '}';
        }
    }
    

    Call it for your data e.g. as

     writeJson(std::cout, proot);
    

    and the output should be

    {
        "Number": 5
    }