developer tip

속성 트리를 사용하여 Boost에서 JSON 배열 만들기

optionbox 2020. 11. 14. 10:09
반응형

속성 트리를 사용하여 Boost에서 JSON 배열 만들기


부스트 속성 트리를 사용하여 JSON 배열을 만들려고합니다.

문서는 말한다 : "JSON 배열이 노드에 매핑되는 각각의 요소가 빈 이름을 가진 자식 노드입니다.."

그래서 빈 이름으로 속성 트리를 만든 다음 호출 write_json(...)하여 배열을 가져 오고 싶습니다 . 그러나 설명서에는 이름이없는 자식 노드를 만드는 방법이 나와 있지 않습니다. 시도 ptree.add_child("", value)했지만 결과는 다음과 같습니다.

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

문서는 적어도 내가 알아낼 수있는 어떤 방법으로도이 점을 다루지 않는 것 같습니다. 누구든지 도울 수 있습니까?


단순 배열 :

#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"
        }
    ]
}

도움이 되었기를 바랍니다


여러분이해야 할 일은이 재미입니다. 이것은 기억에서 나온 것이지만 이와 같은 것이 저에게 효과적입니다.

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 / propert_tree / detail / json_parser_writer.hpp의 다음 줄로 인해 발생합니다.

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

"indent> 0 &&"를 제거하면 배열을 올바르게 작성할 수 있습니다.

생성되는 공간이 마음에 들지 않으면 여기에서 제공 한 패치를 사용할 수 있습니다.


속성 트리를 사용하여 JSON 구조를 표현하기 시작했을 때 해결하지 못한 유사한 문제가 발생했습니다. 또한 설명서에서 속성 트리는 유형 정보를 완전히 지원하지 않습니다.

JSON 값은 값을 포함하는 노드에 매핑됩니다. 그러나 모든 유형 정보가 손실됩니다. 숫자와 리터럴 "null", "true"및 "false"는 단순히 문자열 형식에 매핑됩니다.

이것을 배운 후, 더 완전한 JSON 구현 JSON Spirit으로 전환했습니다 . 이 라이브러리는 JSON 문법 구현을 위해 Boost Spirit을 사용하며 배열을 포함한 JSON을 완벽하게 지원합니다.

대체 C ++ JSON 구현을 사용하는 것이 좋습니다.


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

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

// 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';
}

참고URL : https://stackoverflow.com/questions/2114466/creating-json-arrays-in-boost-using-property-trees

반응형