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