webentwicklung-frage-antwort-db.com.de

Erstellen von JSON-Arrays in Boost mithilfe von Eigenschaftsbäumen

Ich versuche, ein JSON-Array mithilfe von Baumstrukturen für Boost-Eigenschaften zu erstellen.

Die Dokumentation sagt: "JSON-Arrays werden Knoten zugeordnet. Jedes Element ist ein untergeordneter Knoten mit einem leeren Namen."

Ich möchte also einen Eigenschaftsbaum mit leeren Namen erstellen und dann write_json(...) aufrufen, um das Array zu erhalten. In der Dokumentation wird jedoch nicht beschrieben, wie unbenannte untergeordnete Knoten erstellt werden. Ich habe ptree.add_child("", value) ausprobiert, aber das ergibt:

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

Die Dokumentation scheint diesen Punkt nicht anzusprechen, zumindest in keiner Weise, die ich herausfinden kann. Kann jemand helfen?

66
Chris Stucchio

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

ergebnisse in:

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

Array über Objekten:

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

ergebnisse in:

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

hoffe das hilft

101

Was Sie tun müssen, ist dieses Stück Spaß. Dies ist aus der Erinnerung, aber so etwas funktioniert für mich.

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

Aber aufgepasst, es gibt einige Fehler beim Parsen und Schreiben von Json. Einige von denen ich Fehlerberichte eingereicht habe - ohne Antwort :(

BEARBEITEN: um Bedenken bezüglich einer inkorrekten Serialisierung als {"": "", "": ""} auszudrücken

Dies geschieht nur, wenn das Array das Stammelement ist. Der boost ptree writer behandelt alle Root-Elemente als Objekte - niemals Arrays oder Werte. Dies wird durch die folgende Zeile in boost/properties_tree/detail/json_parser_writer.hpp verursacht

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

Wenn Sie "indent> 0 &&" entfernen, können Arrays korrekt geschrieben werden.

Wenn Sie nicht möchten, wie viel Speicherplatz produziert wird, können Sie den von mir bereitgestellten Patch verwenden hier

20

Als ich angefangen habe, Property Tree zur Darstellung einer JSON-Struktur zu verwenden, sind ähnliche Probleme aufgetreten, die ich nicht gelöst habe. Beachten Sie auch, dass die Eigenschaftsbaumstruktur in der Dokumentation die Typinformationen nicht vollständig unterstützt:

JSON-Werte werden Knoten zugeordnet, die den Wert enthalten. Alle Typinformationen gehen jedoch verloren. Zahlen sowie die Literale "null", "true" und "false" werden einfach ihrer Zeichenfolgenform zugeordnet.

Nachdem ich dies gelernt hatte, wechselte ich zur vollständigeren JSON-Implementierung JSON Spirit . Diese Bibliothek verwendet Boost Spirit für die Implementierung der JSON-Grammatik und unterstützt JSON einschließlich Arrays vollständig.

Ich schlage vor, Sie verwenden eine alternative C++ - JSON-Implementierung.

11
Yukiko

In meinem Fall wollte ich ein Array an einer mehr oder weniger willkürlichen Stelle hinzufügen. Erstellen Sie daher wie bei Michaels Antwort einen untergeordneten Baum und füllen Sie ihn mit Array-Elementen:

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

Wenn das untergeordnete Element ausgefüllt wurde, können Sie mit der Funktion put_child() oder add_child() den gesamten untergeordneten Baum wie folgt zum Zielbaum hinzufügen ...

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

die Funktion put_child verwendet einen Pfad und einen Baum für ein Argument und "pfropft" arrayChild in targetTree

6
2NinerRomeo

Ab boost 1.60.0 Besteht das Problem weiterhin.

Bietet eine Umgehung von Python 3 ( Gist ), die direkt nach boost::property_tree::write_json Aufgerufen werden kann.

#!/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