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 regardé dans plusieurs bibliothèques C++ pour créer JSON et elles semblent toutes incroyablement complexes. Je voudrais quelque chose de similaire au JSON.stringify(object) de Javascript . En d'autres termes, il suffit de passer un std::map à lui et de recevoir une chaîne de caractères. La carte pourrait contenir d'autres cartes, vecteurs, des listes, des chaînes, des nombres et des booléens.

Quelle est la meilleure façon de faire ça?

Merci pour votre aide.

Modifier

j'ai regardé ce qui suit:

JSON spirit, jsoncpp, zoolib, JOST, CAJUN, libjson, nosjob, JsonBox, jsonme--

que je comprends que je peux construire un objet JSON séparé comme dans une réponse ci-dessous et convertir en JSON J'aimerais pouvoir stocker mes affaires dans des collections standard et les convertir.

Edit 2

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

y a-t-il une bonne façon de convertir une carte std::contenant des cartes std, des vecteurs std::, des listes std::, des nombres, des chaînes et des bools en JSON sans avoir à changer les types de données ou à copier des données vers un nouveau type de données?

Merci.

52
demandé sur tgt 2011-11-22 03:43:10

8 réponses

JSON Spirit vous permettrait de le faire comme cela:

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" );
write( addr_obj, os, pretty_print );
os.close();

sortie:

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

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

24
répondu sehe 2011-11-22 00:03:13

N'importe quelle bonne bibliothèque C++ JSON devrait faire cela et il est triste de voir qu'ils ne le font pas -- à l'exception de ThorsSerializer et apparemment Nosjob comme mentionné dans cette question .

bien sûr, C++ n'a pas de reflection comme Java, donc vous devez explicitement annoter vos types:

(copié de la Documentation de 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'Usage:

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

en cours d'Exécution:

{
    "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
répondu Sebastian 2018-07-10 23:51:47

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

https://github.com/Mizuchi/acml

Dans votre exemple, vous devez ajouter une ligne comme ceci:

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

afin de dire à la bibliothèque quel membre vous voulez balancer. Depuis c++ n'ont pas de réflexion. Et vous devez donner un moyen de accéder au membre, utilisez le niveau de membre du public ou utilisez la classe ami.

et plus tard vous avez juste besoin de faire sth comme ceci:

chaîne résultat = 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, JSON array n'est pas encore implémenté. Et tout devient ficelle maintenant.

4
répondu ytj 2013-04-20 06:45:40

voulez-vous lister 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 de solution "one-click" pour la sérialisation non plus. N'importe quelle solution vous demandera d'écrire le code additionnel, éventuellement étroitement couplé à la classe que vous voulez sérialiser et dé-sérialiser (que dépend de si vous voulez sérialiser les données non-publiques).

4
répondu Tamás Szelei 2018-08-10 12:18:21

avez-vous regardé les céréales ( http://uscilab.github.io/cereal / )? Il a des archives JSON pour sérialiser vers / depuis JSON en utilisant C++.

un exemple avec des frais généraux minimes (à partir de céréales) peut être trouvé ici sur SO: https://stackoverflow.com/a/22587527/255635

2
répondu Robert 2017-05-23 10:31:06

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

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

c'est pour le moment un projet expérimental, qui peut traiter des types fondamentaux (int, float double), des pointeurs vers les types fondamentaux, des classes, les membres hérités etc ... Il implémente la sérialisation de base std::vector et std::map, ainsi que les instances std::string.

Voir les détails de mise en œuvre ici

0
répondu JBV06 2013-12-15 19:11:48

si la question est toujours actuelle, alors regardez la bibliothèque json_dto , un petit Helper d'en-tête seulement pour convertir des données entre la représentation JSON et les structures c++.

Par exemple les structures suivantes:

struct message_source_t
{
  // Worker thread.
  std::int32_t m_thread_id;

  // Sender.
  std::string m_subsystem;
};

struct message_t
{
  // Who sent a message.
  message_source_t m_from;

  // When the message was sent (unixtime).
  std::tm m_when;

  // Message text.
  std::string m_text;
};

avec l'aide de json_dto vous pouvez créer le JSON suivant:

{
  "from" : 
    {
      "thread_id" : 4242,
      "sybsystem" : "json_dto"
    },
  "when" : "2016.09.28 19:55:00",
  "text" : "Hello world!"
}  

et avec une telle chaîne JSON vous pouvez la convertir en structures.

-1
répondu kola 2018-08-10 12:20:01