How can i decide the datatype Boost Property Tree uses?

835 Views Asked by At

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?

2

There are 2 best solutions below

2
On BEST ANSWER

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
}
0
On

I successfully tried similar things and they worked well without any hacks, see my approach here:

Why does Boost property tree write_json save everything as string? Is it possible to change that?

It requires some effort (you have to provide an own JSON-writer and to specialize some parts of the reader) but it's worth the effort in general since you will also observe a performance gain for a lot of scenarios.