Creating JSON arrays in Boost using Property Trees

大城市里の小女人 提交于 2019-11-28 03:05:38
JustAnotherLinuxNewbie

Simple Array:

#include <boost/property_tree/ptree.hpp>
using boost::property_tree::ptree;

ptree pt;
ptree children;
ptree child1, child2, child3;

child1.put("", 1);
child2.put("", 2);
child3.put("", 3);

children.push_back(std::make_pair("", child1));
children.push_back(std::make_pair("", child2));
children.push_back(std::make_pair("", child3));

pt.add_child("MyArray", children);

write_json("test1.json", pt);

results in:

{
    "MyArray":
    [
        "1",
        "2",
        "3"
    ]
}

Array over Objects:

ptree pt;
ptree children;
ptree child1, child2, child3;


child1.put("childkeyA", 1);
child1.put("childkeyB", 2);

child2.put("childkeyA", 3);
child2.put("childkeyB", 4);

child3.put("childkeyA", 5);
child3.put("childkeyB", 6);

children.push_back(std::make_pair("", child1));
children.push_back(std::make_pair("", child2));
children.push_back(std::make_pair("", child3));

pt.put("testkey", "testvalue");
pt.add_child("MyArray", children);

write_json("test2.json", pt);

results in:

{
    "testkey": "testvalue",
    "MyArray":
    [
        {
            "childkeyA": "1",
            "childkeyB": "2"
        },
        {
            "childkeyA": "3",
            "childkeyB": "4"
        },
        {
            "childkeyA": "5",
            "childkeyB": "6"
        }
    ]
}

hope this helps

What you need to do is this piece of fun. This is from memory, but something like this works for me.

boost::property_tree::ptree root;
boost::property_tree::ptree child1;
boost::property_tree::ptree child2;

// .. fill in children here with what you want
// ...

ptree.push_back( std::make_pair("", child1 ) );
ptree.push_back( std::make_pair("", child2 ) );

But watch out there's several bugs in the json parsing and writing. Several of which I've submitted bug reports for - with no response :(

EDIT: to address concern about it serializing incorrectly as {"":"","":""}

This only happens when the array is the root element. The boost ptree writer treats all root elements as objects - never arrays or values. This is caused by the following line in boost/propert_tree/detail/json_parser_writer.hpp

else if (indent > 0 && pt.count(Str()) == pt.size())

Getting rid of the "indent > 0 &&" will allow it to write arrays correctly.

If you don't like how much space is produced you can use the patch I've provided here

Yukiko

When starting to use Property Tree to represent a JSON structure I encountered similar problems which I did not resolve. Also note that from the documentation, the property tree does not fully support type information:

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.

After learning this, I switched to the more complete JSON implementation JSON Spirit. This library uses Boost Spirit for the JSON grammar implementation and fully supports JSON including arrays.

I suggest you use an alternative C++ JSON implementation.

In my case I wanted to add an array to a more or less arbitrary location, so, like Michael's answer, create a child tree and populate it with array elements:

using boost::property_tree::ptree;

ptree targetTree;
ptree arrayChild;
ptree arrayElement;

//add array elements as desired, loop, whatever, for example
for(int i = 0; i < 3; i++)
{
  arrayElement.put_value(i);
  arrayChild.push_back(std::make_pair("",arrayElement))
}

When the child has been populated, use the put_child() or add_child() function to add the entire child tree to the target tree, like this...

targetTree.put_child(ptree::path_type("target.path.to.array"),arrayChild)

the put_child function takes a path and a tree for an argument and will "graft" arrayChild into targetTree

As of boost 1.60.0, problem persists.

Offering a Python 3 workaround (Gist), which can be syscalled just after boost::property_tree::write_json.

#!/usr/bin/env python3


def lex_leaf(lf: str):
    if lf.isdecimal():
        return int(lf)
    elif lf in ['True', 'true']:
        return True
    elif lf in ['False', 'false']:
        return False
    else:
        try:
            return float(lf)
        except ValueError:
            return lf

def lex_tree(j):
    tj = type(j)
    if tj == dict:
        for k, v in j.items():
            j[k] = lex_tree(v)
    elif tj == list:
        j = [lex_tree(l) for l in j]
    elif tj == str:
        j = lex_leaf(j)
    else:
        j = lex_leaf(j)
    return j


def lex_file(fn: str):
    import json
    with open(fn, "r") as fp:
        ji = json.load(fp)
    jo = lex_tree(ji)
    with open(fn, 'w') as fp:
        json.dump(jo, fp)


if __name__ == '__main__':
    import sys
    lex_file(sys.argv[1])
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!