Using boost property tree to read int array
Asked Answered
T

2

34

I have some JSON with a handful of integer array variables, like so:

{"a": [8, 6, 2], "b": [2, 2, 1]}

I would like to use boost property_tree, for instance:

std::stringstream ss;
boost::property_tree::ptree pt;

ss << "{\"a\": [8, 6, 2], \"b\": [2, 2, 1]}";

boost::property_tree::read_json(ss, pt);
std::vector<int> a = pt.get<std::vector<int> >("a");

This doesn't work, nor does any variation on an int pointer that I've tried. How may I read an array from a property tree?

Tempestuous answered 5/5, 2014 at 20:29 Comment(4)
possible duplicate of Parsing JSON with boost property treeJarvisjary
The answer to that question does not cover the specific case of arrays, so I respectfully disagree. Incidentally, the answer to this question is forthcoming.Tempestuous
But the question itself has code on dealing with arrays, and there's an array in the example data. He extracts the elements using a loop.Jarvisjary
oh, I see what you mean. The question as asked contains the answer to my question. I feel that this isn't obvious, though. Intuitively, it would make sense to me that arrays of primitives would be parsed directly. A concise answer to my question would read something like "each element in a primitive type array is a special case of a child node"Tempestuous
S
35

JSON support, is spotty with boost property tree.

The property tree dataset is not typed, and does not support arrays as such. Thus, the following JSON / property tree mapping is used:

  • JSON objects are mapped to nodes. Each property is a child node.
  • JSON arrays are mapped to nodes. Each element is a child node with an empty name. If a node has both named and unnamed child nodes, it cannot be mapped to a JSON representation.
  • JSON values are mapped to nodes containing the value. However, all type information is lost; numbers, as well as the literals "null", "true" and "false" are simply mapped to their string form.
  • Property tree nodes containing both child nodes and data cannot be mapped.

(from the documentation)

You can iterate the array with a helper function.

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

using boost::property_tree::ptree;

template <typename T>
std::vector<T> as_vector(ptree const& pt, ptree::key_type const& key)
{
    std::vector<T> r;
    for (auto& item : pt.get_child(key))
        r.push_back(item.second.get_value<T>());
    return r;
}

int main()
{
    std::stringstream ss("{\"a\": [8, 6, 2], \"b\": [2, 2, 1]}");

    ptree pt;
    read_json(ss, pt);

    for (auto i : as_vector<int>(pt, "a")) std::cout << i << ' ';
    std::cout << '\n';
    for (auto i : as_vector<int>(pt, "b")) std::cout << i << ' ';
}

See it Live On Coliru. Output:

8 6 2 
2 2 1
Solecism answered 5/5, 2014 at 22:28 Comment(1)
Beautiful solution. Could anyone give the example code using boost_foreach? - I'm not able to use C++11 in my project.Attaway
B
16

Read your a list as follows:

#include <boost/foreach.hpp>
BOOST_FOREACH(boost::property_tree::ptree::value_type &v, pt.get_child("a.")) {
    cout << v.second.data() << endl;
}
Blizzard answered 28/2, 2015 at 7:21 Comment(1)
That's elegant with the trailing . in the path. +1 from meSolecism

© 2022 - 2024 — McMap. All rights reserved.