我正在尝试使用boost属性树创建一个JSON数组。
documentation说:“JSON数组映射到节点。每个元素都是一个空名称的子节点。”
所以我想创建一个空名称的属性树,然后调用write_json(...)
来取出数组。但是,文档没有告诉我如何创建未命名的子节点。我试过了ptree.add_child("", value)
,但这会产生:
Assertion `!p.empty() && "Empty path not allowed for put_child."' failed
文档似乎没有解决这一问题,至少不能以任何方式解决。有人可以帮忙吗?
答案 0 :(得分:97)
简单数组:
#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"
}
]
}
希望这会有所帮助
答案 1 :(得分:20)
你需要做的就是这件乐趣。这是来自记忆,但这样的事情对我有用。
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 writer将所有根元素视为对象 - 绝不是数组或值。这是由boost / properties_tree / detail / json_parser_writer.hpp中的以下行引起的
else if (indent > 0 && pt.count(Str()) == pt.size())
摆脱“缩进&gt; 0&amp;&amp;”将允许它正确地写入数组。
如果您不喜欢产生多少空间,可以使用我提供的补丁here
答案 2 :(得分:11)
当开始使用属性树来表示JSON结构时,我遇到了类似的问题,我没有解决。另请注意,从文档中,属性树不完全支持类型信息:
JSON值映射到包含该值的节点。但是,所有类型信息都丢失了;数字,以及文字“null”,“true”和“false”只是简单地映射到它们的字符串形式。
在得知这一点后,我转而使用更完整的JSON实现JSON Spirit。该库使用Boost Spirit进行JSON语法实现,并完全支持包含数组的JSON。
我建议你使用另一种C ++ JSON实现。
答案 3 :(得分:6)
在我的情况下,我想将一个数组添加到一个或多或少的任意位置,因此,像Michael的回答一样,创建一个子树并用数组元素填充它:
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
答案 4 :(得分: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])
答案 5 :(得分:0)
如果您想要C ++中的JSON,则不需要Boost。借助此library,您可以将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';
}
答案 6 :(得分:0)
对官方文档和上面的回答感到困惑。 以下是我的理解。
属性树由节点组成。
每个节点如下
struct ptree
{
map<key_name,value> data;
vector<pair<key_name,ptree>> children;
};
使用'put'将'value'放入数据中
将“节点”放入带有“push_back”的子节点\
// Write
bt::ptree root;
bt::ptree active;
bt::ptree requested;
bt::ptree n1, n2, n3;
n1.put("name", "Mark");
n1.put("age", 20);
n1.put("job", "aaa");
n2.put("name", "Rosie");
n2.put("age", "19");
n2.put("job", "bbb");
n3.put("name", "sunwoo");
n3.put("age", "10");
n3.put("job", "ccc");
active.push_back ({ "",l1 });
active.push_back ({ "",l2 });
requested.push_back({ "",l3 });
root.push_back ({"active", active});
root.push_back ({"requested", requested});
bt::write_json("E:\\1.json", root);
// READ
bt::ptree root2;
bt::ptree active2;
bt::ptree requested2;
bt::ptree r1, r2, r3;
bt::read_json("E:\\1.json", root2);
// loop children
for (auto& [k,n] : root.get_child("active"))
{
cout << n.get<string>("name", "unknown");
cout << n.get<int> ("age" , 11);
cout << n.get<string>("job" , "man");
cout << endl << flush;
}