web-dev-qa-db-fra.com

Conversion de la classe C++ en JSON

J'aimerais créer une chaîne JSON contenant les variables d'instance de ma classe.

Par exemple,

class Example {  
    std::string string;  
    std::map<std::string, std:string> map;  
    std::vector<int> vector;  
};

deviendrait:

{
    "string":"the-string-value",
    "map": {
        "key1":"val1",
        "key2":"val2"
    },
    "vector":[1,2,3,4]
}

J'ai examiné plusieurs bibliothèques C++ pour la création de JSON et elles semblent toutes incroyablement complexes. Je voudrais quelque chose de similaire à la fonction JSON.stringify(object) de Javascript. En d'autres termes, il suffit de lui passer un std :: map et de recevoir une chaîne. La carte pourrait contenir d’autres cartes, vecteurs, listes, chaînes de caractères, nombres et bools.

Quelle est la meilleure façon de faire cela?

Merci de votre aide.

Modifier

J'ai examiné ce qui suit:

esprit json, jsoncpp, zoolib, JOST, CAJUN, libjson, nosjob, JsonBox, jsonme--

Si je comprends bien, je peux construire un objet JSON distinct comme dans une réponse ci-dessous et convertir en JSON. J'aimerais pouvoir stocker mes données dans des collections standard et les convertir.

Modifier 2

OK, supprimez l’idée de sérialiser une classe car il semble que c’est impossible avec le manque de réflexion de C++.

Existe-t-il un moyen agréable de convertir un fichier std :: map contenant std: maps, std :: vectors, std :: lists, nombres, chaînes et autres en JSON sans avoir à changer de type de données ou à copier des données dans un nouveau type de données?

Merci.

54
tgt

JSON Spirit vous permettrait de le faire comme suit:

Object addr_obj;

addr_obj.Push_back( Pair( "house_number", 42 ) );
addr_obj.Push_back( Pair( "road",         "East Street" ) );
addr_obj.Push_back( Pair( "town",         "Newtown" ) );

ofstream os( "address.txt" );
os.write( addr_obj, os, pretty_print );
os.close();

Sortie: 

{
    "house_number" : 42,
    "road" : "East Street",
    "town" : "Newtown"
}

Le json_map_demo.cpp serait un bon endroit pour commencer, je suppose.

24
sehe

Toute bonne bibliothèque JSON C++ devrait le faire et il est triste de voir qu’elles ne le font pas - à l’exception de ThorsSerializer et apparemment Nosjob comme mentionné dans cette question .

Bien sûr, C++ n'a pas de réflexion comme Java, vous devez donc explicitement annoter vos types:
(copié de la documentation ThorsSerializer)

#include "ThorSerialize/JsonThor.h"
#include "ThorSerialize/SerUtil.h"
#include <map>
#include <vector>
#include <string>
#include <iostream>

class Example {
    std::string string;
    std::map<std::string, std::string> map;
    std::vector<int> vector;

    // Allow access to the class by the serialization library.
    friend class ThorsAnvil::Serialize::Traits<Example>;

    public:
        Example(std::string const& s, std::map<std::string, std::string> const& m, std::vector<int> const& v)
            : string(s), map(m), vector(v)
        {}
};

// Define what members need to be serilizable
ThorsAnvil_MakeTrait(Example, string, map, vector);

Exemple d'utilisation:

int main()
{
    using ThorsAnvil::Serialize::jsonExport;
    using ThorsAnvil::Serialize::jsonImport;


    Example     e1 {"Some Text", {{"ace", "the best"}, {"king", "second best"}}, {1 ,2 ,3, 4}};

    // Simply serialize object to json using a stream.
    std::cout << jsonExport(e1) << "\n";

    // Deserialize json text from a stream into object.
    std::cin  >> jsonImport(e1);
}

Fonctionnement:

{
    "string": "Some Text",
    "map":
    {
        "ace": "the best",
        "king": "second best"
    },
    "vector": [ 1, 2, 3, 4]
}

Vous ne pouvez pas faire mieux que cela en C++. 

14
Sebastian

J'ai écrit une bibliothèque qui a été conçue pour résoudre votre problème . Cependant, il s'agit d'un projet très nouveau, pas assez stable . N'hésitez pas à jeter un coup d'œil, la page d'accueil est ici ::

https://github.com/Mizuchi/acml

Dans votre exemple, vous devez ajouter une ligne comme celle-ci:

ACML_REGISTER(Example, ,(string)(map)(vector));

afin de dire à la bibliothèque quel membre vous voulez vider . Puisque C++ n’a pas de réflexion . Et vous devez donner un moyen d’accéder au membre.

Et plus tard, il vous suffit de faire comme ça:

string result = acml :: json :: dumps (any_object);

deviendrait::

{
    "string": "the-string-value",
    "map":
    {
        "key1": "val1",
        "key2": "val2"
    },
    "vector":
    {
        "type": "std::vector",
        "size": "4",
        "0": "1",
        "1": "2",
        "2": "3",
        "3": "4"
    }
}

Comme vous le voyez, le tableau JSON n'est pas encore implémenté . Et tout devient chaîne maintenant.

4
ytj

Voulez-vous JSON-ify une carte ou un objet? (votre exemple montre une classe, mais vous dites une carte). Pour une carte, consultez cette bibliothèque - JSON Spirit .

Pour les objets: Il n'y a pas de support de réflexion en C++ (à part le très limité RTTI), donc il n'y a pas non plus de solution "en un clic" pour la sérialisation. Toute solution nécessite que vous écriviez du code supplémentaire, éventuellement étroitement couplé, à la classe que vous souhaitez sérialiser et désérialiser (cela dépend si vous souhaitez sérialiser des données non publiques).

4
Tamás Szelei

Avez-vous examiné les céréales ( http://uscilab.github.io/cereal/ )? Il possède des archives JSON pour la sérialisation vers/à partir de JSON à l'aide de C++.

Vous trouverez un exemple avec des frais généraux minimes (de céréales) à l'adresse SO: https://stackoverflow.com/a/22587527/255635

2
Robert

J'ai écrit une bibliothèque expérimentale qui peut faire le travail, mais elle nécessite une description externe des structures et de la hiérarchie des classes. Il utilise GCCXML pour créer un dictionnaire xml, utilisé pour la désérialisation de la sérialisation:

http://code.google.com/p/cjson/

Il s’agit pour le moment d’un projet expérimental traitant des types fondamentaux (int, float double), des pointeurs sur les types fondamentaux, des classes, des membres hérités, etc. std :: instances de chaîne.

Voir les détails pour la mise en œuvre ici

1
JBV06

Vous pouvez utiliser Boost.PropertyTree .

#include <map>
#include <vector>
#include <string>
#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

namespace pt = boost::property_tree;

int main() {
    // Create an empty property tree object.
    pt::ptree tree;

    // Put a string value into the tree.
    tree.put("string", "the-string-value");

    // Put a map object into the tree.
    pt::ptree child1;
    std::map<std::string, std::string> map = {{"key1", "val1"},
                                              {"key2", "val2"}};
    for (auto &p : map) {
        child1.add(p.first, p.second);
    }
    tree.add_child("map", child1);

    // Put a vector of numbers into the tree
    pt::ptree child2;
    std::vector<int> vector = {1, 2, 3, 4};
    for (auto &v : vector) {
        pt::ptree item;
        item.put("", v);
        child2.Push_back(std::make_pair("", item));
    }
    tree.add_child("vector", child2);

    // Write property tree to JSON file
    pt::write_json("output.json", tree);

    return 0;
}

Sortie:

{
    "string": "the-string-value",
    "map": {
        "key1": "val1",
        "key2": "val2"
    },
    "vector": [
        "1",
        "2",
        "3",
        "4"
    ]
}
0
mect