Подтвердить что ты не робот

Преобразование класса С++ в JSON

Я хотел бы создать строку 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]
}

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

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

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

Edit

Я рассмотрел следующее:

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

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

Изменить 2

Хорошо, отбросьте идею сериализации класса, так как кажется невозможным с отсутствием рефлекса С++.

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

Спасибо.

4b9b3361

Ответ 1

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.

Ответ 2

Любая хорошая библиотека CNS 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++.

Ответ 3

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

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

Ответ 4

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

https://github.com/Mizuchi/acml

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

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

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

И позже вам просто нужно сделать так:

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 еще не реализован. И теперь все становится строкой.

Ответ 5

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

Пример с минимальными накладными расходами (из зерновых) можно найти здесь на SO: fooobar.com/questions/112043/...

Ответ 6

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

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

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

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

Ответ 7

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

Ответ 8

this python script создает классы С++ pod с одним элементом для каждого свойства json

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

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

Ответ 9

Если вопрос по-прежнему актуальен, посмотрите на библиотеку 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, вы можете преобразовать ее в структуры.