json boost boost-propertytree

¿Por qué impulsar el árbol de propiedades write_json guarda todo como una cadena? ¿Es posible cambiar eso?



boost boost-propertytree (5)

Boost confirma que su implementación no tiene un 100% de conformidad con el estándar JSON. Consulte el siguiente enlace para ver su explicación: Hacer una variante de preeree que preserve los tipos JSON es un plan futuro, pero lejano. !

Estoy tratando de serializar usando el árbol de propiedades boost write_json, guarda todo como cadenas, no es que los datos sean incorrectos, pero necesito enviarlos explícitamente cada vez y quiero usarlos en otro lugar. (como en python u otra biblioteca C ++ json (no boost))

aquí hay un código de muestra y lo que obtengo dependiendo de la configuración regional:

boost::property_tree::ptree root, arr, elem1, elem2; elem1.put<int>("key0", 0); elem1.put<bool>("key1", true); elem2.put<float>("key2", 2.2f); elem2.put<double>("key3", 3.3); arr.push_back( std::make_pair("", elem1) ); arr.push_back( std::make_pair("", elem2) ); root.put_child("path1.path2", arr); std::stringstream ss; write_json(ss, root); std::string my_string_to_send_somewhare_else = ss.str();

y my_string_to_send_somewhere_else es sth. Me gusta esto:

{ "path1" : { "path2" : [ { "key0" : "0", "key1" : "true" }, { "key2" : "2.2", "key3" : "3.3" } ] } }

¿Hay alguna forma de guardarlos como valores, como: "key1" : true o "key2" : 2.2 ?


Como tenemos typedef basic_ptree <std :: string, std :: string> ptree; en las bibliotecas de impulso, boost siempre serializará cada valor como una cadena y analizará todos los valores en una cadena equivalente.


Desde el JSON de salida, está claro que el serializador serializa todo en cadenas usando algún tipo de método .toString (), es decir, desconoce el tipo de cada miembro y, por lo tanto, incluye todo en "".

Consulte Creación de matrices JSON en Boost usando Property Trees para obtener más información sobre este problema.


La solución más simple y más limpia que pude encontrar fue generar el JSON con marcadores de posición y al final cadena reemplazar con el valor real eliminando las comillas adicionales.

static string buildGetOrdersCommand() { ptree root; ptree element; element.put<string>("pendingOnly", ":pendingOnly"); element.put<string>("someIntValue", ":someIntValue"); root.put("command", "getOrders"); root.put_child("arguments", element); std::ostringstream buf; write_json(buf, root, false); buf << std::endl; string json = buf.str(); replace(json, ":pendingOnly", "true"); replace(json, ":someIntValue", std::to_string(15)); return json; } static void replace(string& json, const string& placeholder, const string& value) { boost::replace_all<string>(json, "/"" + placeholder + "/"", value); }

Y el resultado es

{"comando": "getOrders", "argumentos": {"pendingOnly": true, "someIntValue": 15}}


Ok, lo he resuelto así, (por supuesto, no será apto para todos, ya que es un poco un truco, que necesitan más trabajo).

Escribí mi propia función write_json (simplemente copié los archivos, json_parser.hpp y json_parser_write.hpp en mi proyecto) y modifiqué las siguientes líneas en json_parser_write.hpp :

  1. línea comentada 37 - escapando de la cita ''"''
  2. cambió la línea 76 - para que ya no agregue comillas: stream << Ch(''"'') << data << Ch(''"''); ==> stream << data; stream << Ch(''"'') << data << Ch(''"''); ==> stream << data;

Entonces, los valores se guardarán correctamente excepto por cadenas, así que escribí un traductor personalizado para ello:

template <typename T> struct my_id_translator { typedef T internal_type; typedef T external_type; boost::optional<T> get_value(const T &v) { return v.substr(1, v.size() - 2) ; } boost::optional<T> put_value(const T &v) { return ''"'' + v +''"''; } };

y simplemente cadena guardada usando:

elem2.put<std::string>("key2", "asdf", my_id_translator<std::string>());

programa completo:

#include <iostream> #include <string> #include <sstream> #include <boost/property_tree/ptree.hpp> #include "property_tree/json_parser.hpp" // copied the headers template <typename T> struct my_id_translator { typedef T internal_type; typedef T external_type; boost::optional<T> get_value(const T &v) { return v.substr(1, v.size() - 2) ; } boost::optional<T> put_value(const T &v) { return ''"'' + v +''"''; } }; int main(int, char *[]) { using namespace std; using boost::property_tree::ptree; using boost::property_tree::basic_ptree; try { ptree root, arr,elem2; basic_ptree<std::string, std::string> elem1; elem1.put<int>("int", 10 ); elem1.put<bool>("bool", true); elem2.put<double>("double", 2.2); elem2.put<std::string>("string", "some string", my_id_translator<std::string>()); arr.push_back( std::make_pair("", elem1) ); arr.push_back( std::make_pair("", elem2) ); root.put_child("path1.path2", arr); std::stringstream ss; write_json(ss, root); std::string my_string_to_send_somewhere_else = ss.str(); cout << my_string_to_send_somewhere_else << endl; } catch (std::exception & e) { cout << e.what(); } return 0; }

resultado :)

{ "path1": { "path2": [ { "int": 10, "bool": true }, { "double": 2.2, "string": "some string" } ] } }