Преобразование класса С++ в 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 без необходимости изменять типы данных или копировать данные в новый тип данных?
Спасибо.
Ответы
Ответ 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, вы можете преобразовать ее в структуры.