Pourquoi boost property tree write JSON sauve tout en chaîne? Est-il possible de changer cela?

j'essaie de sérialiser en utilisant boost property tree write_json, il sauve tout comme les chaînes, ce n'est pas que les données sont fausses, mais je dois les lancer explicitement à chaque fois et je veux les utiliser ailleurs. (comme dans python ou autre bibliothèque C++ json (non boost))

voici un exemple de code et ce que j'obtiens en fonction de la localisation:

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

et my_string_to_send_somewhere_else est sth. comme ceci:

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

est là de toute façon pour les enregistrer comme valeurs, comme: "key1" : true ou "key2" : 2.2 ?

53
demandé sur dandan78 2010-05-18 12:52:56

5 réponses

Ok, je l'ai résolu comme ceci, (bien sûr, il ne sera pas suite pour tout le monde, car il est un peu d'un piratage, qui ont besoin de plus de travail).


j'ai écrit ma propre fonction write_json (j'ai simplement copié les fichiers, json_parser.hpp et json_parser_write.hpp à mon projet) et j'ai modifié les lignes suivantes dans json_parser_write.hpp :

  1. , a commenté la ligne 37 - s'échapper de la citation '"'
  2. a changé la ligne 76 - de sorte que il n'est pas ajouter des citations plus: stream << Ch('"') << data << Ch('"'); ==> stream << data;

puis les valeurs seront sauvegardées correctement sauf pour les chaînes, donc j'ai écrit le traducteur personnalisé pour cela:

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 +'"'; }
};

et simplement sauvé chaîne en utilisant:

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

programme complet:

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

résultat:)

{
    "path1":
    {
        "path2":
        [
            {
                "int": 10,
                "bool": true
            },
            {
                "double": 2.2,
                "string": "some string"
            }
        ]
    }
}
33
répondu pprzemek 2017-09-23 09:34:40

Boost confirme que sa mise en œuvre n'est pas 100% conforme à la norme JSON. Consulter le lien suivant pour voir leur explication: faire une variante de ptree qui préserve les types JSON est un plan futur, mais loin de là. !

9
répondu Alex Sed 2014-11-05 02:38:15

la solution la plus simple et la plus propre que j'ai pu trouver a été de générer le JSON avec des espaces réservés et dans la chaîne de fin de remplacer par la valeur réelle en sautant les citations supplémentaires.

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

et le résultat est

{"commande": "getOrders", "arguments": {"pendingOnly": true, "someIntValue": 15}}

4
répondu sbile 2015-02-28 11:29:11

comme nous l'avons typedef basic_ptree ptree; dans les bibliothèques boost, boost sérialisera toujours chaque valeur en chaîne et analysera toutes les valeurs en équivalent chaîne.

3
répondu Josbert Lonnee 2014-03-10 11:23:42

de la sortie JSON il est clair que le serializer sérialise tout aux chaînes en utilisant une sorte de .ToString () méthode - c'est-à-dire, son ignorance du type de chaque membre et donc entoure tout dans " ".

Voir la Création de tableaux JSON dans Boost en utilisant la Propriété des Arbres pour en savoir plus sur ce problème .

2
répondu Sean Kinsey 2017-05-23 11:54:30