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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2114466/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 22:08:43  来源:igfitidea点击:

Creating JSON arrays in Boost using Property Trees

c++jsonboostboost-propertytree

提问by Chris Stucchio

I'm trying to create a JSON array using boost property trees.

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

The documentationsays: "JSON arrays are mapped to nodes. Each element is a child node with an empty name."

文件说:“JSON数组被映射到节点的每个元素与空名称的子节点。”

So I'd like to create a property tree with empty names, then call write_json(...)to get the array out. However, the documentation doesn't tell me how to create unnamed child nodes. I tried ptree.add_child("", value), but this yields:

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

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

The documentation doesn't seem to address this point, at least not in any way I can figure out. Can anyone help?

文档似乎没有解决这一点,至少我无法弄清楚。任何人都可以帮忙吗?

回答by 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

希望这可以帮助

回答by Michael Anderson

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 :(

但是要注意 json 解析和编写中有几个错误。其中一些我已经提交了错误报告 - 没有回应:(

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

这只发生在数组是根元素时。boost ptree 编写器将所有根元素视为对象 - 从不使用数组或值。这是由 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.

摆脱“缩进> 0 &&”将允许它正确写入数组。

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

如果你不喜欢产生多少空间,你可以使用我在这里提供的补丁

回答by 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 结构时,我遇到了类似的问题,但我没有解决。另请注意,从文档中可以看出,属性树并不完全支持类型信息:

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.

JSON 值映射到包含该值的节点。但是,所有类型信息都丢失了;数字以及文字“null”、“true”和“false”都简单地映射到它们的字符串形式。

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.

学完这个,我切换到了更完整的 JSON 实现JSON Spirit。该库使用 Boost Spirit 进行 JSON 语法实现,并完全支持包括数组在内的 JSON。

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

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

回答by 2NinerRomeo

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...

当孩子被填充后,使用put_child()oradd_child()函数将整个子树添加到目标树中,就像这样......

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

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

回答by Thane Plummer

If you want JSON in C++, there's no need for Boost. With this libraryyou can get JSON as a first class data type that behaves like an STL container.

如果您想要 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';
}

回答by Patrizio Bertoni

As of boost 1.60.0, problem persists.

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

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

提供一种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])