web-dev-qa-db-fra.com

Création de tableaux JSON dans Boost à l'aide d'arbres de propriétés

J'essaie de créer un tableau JSON en utilisant des arbres de propriétés boost.

documentation dit: "Les tableaux JSON sont mappés à des nœuds. Chaque élément est un nœud enfant avec un nom vide."

Je voudrais donc créer une arborescence de propriétés avec des noms vides, puis appeler write_json(...) pour sortir le tableau. Cependant, la documentation ne me dit pas comment créer des nœuds enfants sans nom. J'ai essayé ptree.add_child("", value), mais cela donne:

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

La documentation ne semble pas aborder ce point, du moins pas du tout que je puisse comprendre. Quelqu'un peut-il aider?

66
Chris Stucchio

Tableau simple:

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

résulte en:

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

Tableau sur les objets:

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

résulte en:

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

j'espère que cela t'aides

101

Ce que vous devez faire, c'est ce morceau de plaisir. C'est de mémoire, mais quelque chose comme ça fonctionne pour moi.

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

Mais attention, il y a plusieurs bogues dans l'analyse et l'écriture json. Plusieurs desquels j'ai soumis des rapports de bogues pour - sans réponse :(

EDIT: pour résoudre le problème de sérialisation incorrecte en tant que {"": "", "": ""}

Cela ne se produit que lorsque le tableau est l'élément racine. Le rédacteur boost ptree traite tous les éléments racine comme des objets - jamais des tableaux ou des valeurs. Cela est dû à la ligne suivante dans boost/propert_tree/detail/json_parser_writer.hpp

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

Se débarrasser de "indent> 0 &&" lui permettra d'écrire correctement les tableaux.

Si vous n'aimez pas l'espace produit, vous pouvez utiliser le patch que j'ai fourni ici

20
Michael Anderson

Lorsque j'ai commencé à utiliser l'arborescence des propriétés pour représenter une structure JSON, j'ai rencontré des problèmes similaires que je n'ai pas résolus. Notez également que dans la documentation, l'arborescence des propriétés ne prend pas entièrement en charge les informations de type:

Les valeurs JSON sont mappées aux nœuds contenant la valeur. Cependant, toutes les informations de type sont perdues; les nombres, ainsi que les littéraux "null", "true" et "false" sont simplement mappés à leur forme de chaîne.

Après avoir appris cela, je suis passé à l'implémentation JSON plus complète JSON Spirit . Cette bibliothèque utilise Boost Spirit pour l'implémentation de la grammaire JSON et prend entièrement en charge JSON, y compris les tableaux.

Je vous suggère d'utiliser une implémentation alternative C++ JSON.

11
Yukiko

Dans mon cas, je voulais ajouter un tableau à un emplacement plus ou moins arbitraire, alors, comme la réponse de Michael, créez un arbre enfant et remplissez-le avec des éléments du tableau:

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

Lorsque l'enfant a été rempli, utilisez la fonction put_child() ou add_child() pour ajouter l'arborescence enfant entière à l'arborescence cible, comme ceci ...

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

la fonction put_child prend un chemin et un arbre pour un argument et "greffe" arrayChild dans targetTree

6
2NinerRomeo

À partir du boost 1.60.0, le problème persiste.

Offrant un Python 3 solution de contournement ( Gist ), qui peut être syscallée juste après 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 __== '__main__':
    import sys
    Lex_file(sys.argv[1])
0
Patrizio Bertoni