Преобразование класса C ++ в JSON - PullRequest
54 голосов
/ 22 ноября 2011

Я хотел бы создать строку JSON, содержащую переменные экземпляра моего класса.

Например,

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

станет:

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

Я изучил несколько библиотек C ++ для создания JSON, и все они кажутся невероятно сложными. Я хотел бы что-то похожее на Javascript JSON.stringify(object). Другими словами, просто передайте ему std :: map и получите строку. Карта может содержать другие карты, векторы, списки, строки, числа и bools.

Какой самый лучший способ сделать это?

Спасибо за вашу помощь.

Редактировать

Я изучил следующее:

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

Как я понимаю, я могу создать отдельный объект JSON, как показано в ответе ниже, и преобразовать в JSON. Я хотел бы иметь возможность хранить свои вещи в стандартных коллекциях и конвертировать.

Редактировать 2

Ладно, отбросьте идею сериализации класса, так как кажется, что это невозможно без C ++.

Есть ли хороший способ преобразовать std :: map, содержащий std: maps, std :: vectors, std :: lists, numbers, strings и bools, в JSON без необходимости изменения типов данных или копирования данных в новый тип данных

Спасибо.

Ответы [ 9 ]

24 голосов
/ 22 ноября 2011

JSON Spirit позволит вам сделать это так:

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

Вывод:

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

json_map_demo.cpp было бы неплохо начать, я полагаю.

16 голосов
/ 14 ноября 2013

Любая хорошая библиотека C ++ JSON должна делать это, и грустно видеть, что они этого не делают - за исключением ThorsSerializer и, очевидно, Nosjob , как упомянуто в этом вопрос .

Конечно, C ++ не имеет отражения, как Java, поэтому вы должны явно аннотировать ваши типы:
(скопировано из документации 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);

Пример использования:

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

Продолжительность:

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

Вы не можете добиться большего успеха, чем это в C ++.

4 голосов
/ 26 января 2012

Я написал библиотеку, которая предназначена для решения вашей проблемы. Однако это очень новый проект, недостаточно стабильный. Не стесняйтесь взглянуть, домашняя страница здесь ::

https://github.com/Mizuchi/acml

В вашем примере вы должны добавить одну строку, например:

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

, чтобы указать библиотеке, какого члена вы хотите сбросить. Так как C ++ не имеет никакого отражения. И вы должны дать способ доступа к члену, либо используйте открытый уровень участника, либо используйте класс друга.

А потом вам просто нужно сделать что-то вроде этого:

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

станет ::

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

Как видите, массив JSON еще не реализован. И теперь все становится строкой.

4 голосов
/ 22 ноября 2011

Хотите ли вы JSON-карту или объект? (ваш пример показывает класс, но вы говорите карту). Для карты, проверьте эту библиотеку - JSON Spirit .

Для объектов: в C ++ нет поддержки отражений (кроме очень ограниченного RTTI), поэтому для сериализации также не существует решения «одним щелчком». Любое решение потребует от вас написать дополнительный, возможно, тесно связанный код для класса, который вы хотите сериализовать и десериализовать (это зависит от того, хотите ли вы сериализовать непубличные данные).

2 голосов
/ 09 февраля 2016

Вы смотрели на зерновые (http://uscilab.github.io/cereal/)? У него есть архивы JSON для сериализации в / из JSON с использованием C ++.

Пример с минимальными накладными расходами (из хлопьев) можно найти здесь на SO: https://stackoverflow.com/a/22587527/255635

1 голос
/ 15 декабря 2013

Я написал экспериментальную библиотеку, которая может выполнять эту работу, но требует внешнего описания структур и иерархии классов.Он использует GCCXML для создания словаря xml, используемого для десериализации сериализации:

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

На данный момент это экспериментальный проект, который может работать с фундаментальными типами (int, float double).), указатели на базовые типы, классы, унаследованные члены и т. д. ... Он реализует базовую сериализацию std :: vector и std :: map, а также экземпляры std :: string.

Подробности реализации здесь

0 голосов
/ 17 декабря 2018

Вы можете использовать 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;
}

Выход:

{
    "string": "the-string-value",
    "map": {
        "key1": "val1",
        "key2": "val2"
    },
    "vector": [
        "1",
        "2",
        "3",
        "4"
    ]
}
0 голосов
/ 06 октября 2016

Если вопрос все еще актуален, посмотрите на библиотеку json_dto , небольшой помощник только для заголовка для преобразования данных между представлением JSON и структурами c ++.

Например, имеющие следующие структуры:

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

с помощью json_dto вы можете создать следующий JSON:

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

И, используя такую ​​строку JSON, вы можете преобразовать ее в структуры.

0 голосов
/ 04 ноября 2015

этот скрипт Python генерирует классы p ++ c ++ с одним членом для каждого свойства json

вы хотите совсем противоположное, но тривиально создать класс отображения, который выполняет как загрузку, так и сохранение

сгенерированный код использует внешнюю библиотеку json parser

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...