web-dev-qa-db-ja.com

プロパティツリーを使用してBoostでJSON配列を作成する

ブーストプロパティツリーを使用してJSON配列を作成しようとしています。

documentation は、「JSON配列はノードにマップされます。各要素は空の名前を持つ子ノードです。」

そこで、空の名前でプロパティツリーを作成し、write_json(...)を呼び出して配列を取得したいと思います。ただし、ドキュメントでは、名前のない子ノードの作成方法については説明していません。私はptree.add_child("", value)を試しましたが、これは以下をもたらします:

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

ドキュメントは、少なくとも私が理解できる方法で、この点に対処していないようです。誰でも助けることができますか?

66
Chris Stucchio

単純な配列:

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

お役に立てれば

101

あなたがする必要があるのは、この楽しさです。これは記憶からですが、このようなものは私のために動作します。

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の解析と記述にはいくつかのバグがあることに注意してください。いくつかのバグ報告を提出しました-応答なしで:(

編集:{"": ""、 "": ""}として誤ってシリアル化することに関する懸念に対処するため

これは、配列がルート要素である場合にのみ発生します。ブーストptreeライターは、すべてのルート要素をオブジェクトとして扱います。配列や値は扱いません。これは、boost/propert_tree/detail/json_parser_writer.hppの次の行が原因です。

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

「インデント> 0 &&」を削除すると、配列を正しく書き込むことができます。

どれだけのスペースが生成されるか気に入らない場合は、提供したパッチを使用できます here

20

プロパティツリーを使用してJSON構造を表現し始めたとき、解決しなかった同様の問題が発生しました。また、ドキュメントから、プロパティツリーは型情報を完全にはサポートしていないことに注意してください。

JSON値は、値を含むノードにマップされます。ただし、すべてのタイプ情報は失われます。数字、およびリテラル「null」、「true」、「false」は、単に文字列形式にマッピングされます。

これを学んだ後、より完全なJSON実装に切り替えました JSON Spirit 。このライブラリは、JSON文法の実装にBoost Spiritを使用し、配列を含むJSONを完全にサポートします。

別のC++ JSON実装を使用することをお勧めします。

11
Yukiko

私の場合、多かれ少なかれ任意の場所に配列を追加したかったので、マイケルの答えのように、子ツリーを作成し、それに配列要素を入力します。

_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に「グラフト」します

6
2NinerRomeo

boost 1.60.0現在、問題は継続しています。

Python 3回避策( Gist )を提供します。これはboost::property_tree::write_jsonの直後にsyscallできます。

#!/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 __== '__main__':
    import sys
    Lex_file(sys.argv[1])
0