使用属性树在Boost中创建JSON数组


69

我正在尝试使用boost属性树创建一个JSON数组。

文档说:“ JSON数组被映射到节点。每个元素都是一个具有空名称的子节点。”

因此,我想用空名称创建一个属性树,然后调用write_json(...)将数组取出。但是,文档没有告诉我如何创建未命名的子节点。我尝试过ptree.add_child("", value),但这会产生:

Assertion `!p.empty() && "Empty path not allowed for put_child."' failed

该文档似乎没有解决这一点,至少我无法确定。有人可以帮忙吗?

Answers:


110

简单数组:

#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);

结果是:

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

物件上方的阵列:

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);

结果是:

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

希望这可以帮助


6
请注意,数字被编码为字符串而不是数字。
路加福音

嗨,@ Luke,我的琴弦有这个问题。如何将它们编码为数字?
亚历杭德罗(Alejandro)

3
使用boost库时找不到合适的解决方案。我改为使用RapidJSON。
路加福音

这有很多限制:您不能仅使用单个元素创建数组,并且多次重复相同的元素对我也不起作用。
Dietr '19

有一种更简单的方法可以生成不需要中间子对象的纯值数组:children.push_back(ptree :: value_type(“”,“ 1”)); 该值必须设置为字符串格式
pcdangio

22

您需要做的就是这个乐趣。这是从记忆中来的,但是类似的东西对我有用。

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 ) );

但是请注意,json解析和写入过程中存在一些错误。我已经提交了其中的一些错误报告-没有回应:(

编辑:解决有关将其错误地序列化为{“”:“”,“”:“”}的问题

仅当数组是根元素时才会发生这种情况。boost ptree编写器将所有根元素都视为对象,而不是数组或值。这是由于boost / propert_tree / detail / json_parser_writer.hpp中的以下行引起的

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

摆脱“缩进> 0 &&”将使其正确写入数组。

如果您不喜欢产生多少空间,可以使用我在此处提供的补丁


这是不对的。转储到JSON之后,而不是获取数组,得到的是:{“”:“”,“”:“”}。
克里斯·斯托基奥

更新了帖子,以反映这种情况的发生原因以及解决方法。
Michael Anderson 2010年

可悲的报告,似乎仍无法创建数组作为在1.53.0根元素。
和解者

1
您也可以尝试直接调用内部帮助程序,并伪造缩进。boost :: property_tree :: json_parser :: write_json_helper(stream,root,1,false);
加博尔

@Gabor:您为什么要通过pretty=false那里?它可以工作,但是默认设置write_json为漂亮打印。
MSalters,

11

当开始使用属性树来表示JSON结构时,我遇到了类似的问题,但我没有解决。另请注意,从文档中,属性树不完全支持类型信息:

JSON值映射到包含该值的节点。但是,所有类型的信息都会丢失。数字以及文字“ null”,“ true”和“ false”仅映射到其字符串形式。

了解了这一点之后,我切换到了更完整的JSON实现JSON Spirit。该库使用Boost Spirit进行JSON语法实现,并完全支持JSON(包括数组)。

我建议您使用替代的C ++ JSON实现。


1
自从我写了这个答案以来,有很多新图书馆。这是我最近遇到的一个不错的例子
Yukiko

6

就我而言,我想将数组添加到一个或多或少的任意位置,因此,就像迈克尔的回答一样,创建一个子树并用数组元素填充它:

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))
}

填充子树后,使用put_child()add_child()函数将整个子树添加到目标树,如下所示...

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

put_child函数采用路径和树作为参数,并将arrayChild“嫁接到” targetTree中


1

如果您想要C ++中的JSON,则不需要Boost。使用此库,您可以将JSON用作行为类似于STL容器的一流数据类型。

// Create JSON on the fly.
json j2 = {
  {"pi", 3.141},
  {"happy", true},
  {"name", "Niels"},
  {"nothing", nullptr},
  {"answer", {
    {"everything", 42}
  }},
  {"list", {1, 0, 2}},
  {"object", {
    {"currency", "USD"},
    {"value", 42.99}
  }}
};

// Or treat is as an STL container; create an array using push_back
json j;
j.push_back("foo");
j.push_back(1);
j.push_back(true);

// also use emplace_back
j.emplace_back(1.78);

// iterate the array
for (json::iterator it = j.begin(); it != j.end(); ++it) {
  std::cout << *it << '\n';
}

0

截至boost 1.60.0,问题仍然存在。

提供一种Python 3变通办法(Gist),可以在之后调用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])
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.