为什么Boost属性树write_json会将所有内容保存为字符串?有可能改变吗?

为什么Boost属性树write_json会将所有内容保存为字符串?有可能改变吗?,json,boost,boost-propertytree,Json,Boost,Boost Propertytree,我尝试使用boost属性树write_json进行序列化,它将所有内容保存为字符串,并不是因为数据错误,而是每次都需要显式转换它们,我希望在其他地方使用它们。(如Python或其他C++ JSON(非Boost)库) 下面是一些示例代码,以及根据区域设置得到的代码: boost::property_tree::ptree root, arr, elem1, elem2; elem1.put<int>("key0", 0); elem1.put<bool>("key1",

我尝试使用boost属性树write_json进行序列化,它将所有内容保存为字符串,并不是因为数据错误,而是每次都需要显式转换它们,我希望在其他地方使用它们。(如Python或其他C++ JSON(非Boost)库)

下面是一些示例代码,以及根据区域设置得到的代码:

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();
是否仍然可以将它们保存为值,例如:
“key1”:true
“key2”:2.2

从输出的JSON可以清楚地看出,序列化程序使用某种.toString()方法将所有内容序列化为字符串—也就是说,它不知道每个成员的类型,因此将所有内容都封装在“”中


有关此问题的更多信息,请参阅。

好的,我已经这样解决了它(当然,它不适合所有人,因为它有点像黑客,需要进一步的工作)


我已经编写了自己的
write_json
函数(只需将文件、
json_parser.hpp
json_parser_write.hpp
复制到我的项目中),并修改了
json_parser_write.hpp
中的以下行:

  • 注释第37行-转义引号''
  • 更改了第76行-以便不再添加引号:
    stream因为我们在boost库中有typedef basic_ptree ptree;boost总是将每个值序列化为字符串,并将所有值解析为等效字符串。

    boost确认其实现与JSON标准没有100%的一致性。请查看以下链接以查看其解释:

    我能想到的最简单、最干净的解决方案是生成带有占位符的JSON,并在最后用实际值替换字符串,去掉多余的引号

    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);
    }
    
    静态字符串buildGetOrdersCommand(){
    树根;
    稀土元素;
    元素。put(“pendingOnly”,“:pendingOnly”);
    元素。put(“someIntValue”,“someIntValue”);
    root.put(“命令”、“获取命令”);
    root.put_child(“参数”,元素);
    std::ostringstream buf;
    写入_json(buf、root、false);
    
    buf为了解决这个问题,我在utils中添加了另一个函数:

    #include <string>
    #include <regex>
    #include <boost/property_tree/json_parser.hpp>
    
    namespace bpt = boost::property_tree;
    typedef bpt::ptree JSON;
    namespace boost { namespace property_tree {
        inline void write_jsonEx(const std::string & path, const JSON & ptree)
        {
            std::ostringstream oss;
            bpt::write_json(oss, ptree);
            std::regex reg("\\\"([0-9]+\\.{0,1}[0-9]*)\\\"");
            std::string result = std::regex_replace(oss.str(), reg, "$1");
    
            std::ofstream file;
            file.open(path);
            file << result;
            file.close();
        }
    } }
    
    #包括
    #包括
    #包括
    名称空间bpt=boost::属性树;
    typedef-bpt::ptree-JSON;
    名称空间boost{名称空间属性_树{
    内联void write_jsonEx(const std::string&path,const JSON&ptree)
    {
    std::ostringstream oss;
    bpt::write_json(oss,ptree);
    std::regex reg(“\\\”([0-9]+\.{0,1}[0-9]*)\\\”;
    std::string result=std::regex_replace(oss.str(),reg,“$1”);
    流文件的std::of;
    打开(路径);
    
    file对我来说,所有需要显式自定义字符串转换器的解决方案似乎都很容易出错,因为它有时可能会忘记。通过继承为属性树的put方法提供某种重载方式来隐式处理这一问题会很好,但这不可能以健壮的方式实现,因为它是一个模板您必须确保树的所有方法都具有完全的协方差性。此外,如果可能的话,通常应避免将boost库的内容更改为一种解决方法

    到目前为止,我发现没有黑客攻击的最健壮的方法是(从C++11开始):

    • 将boost属性树与
    • 为你的变体提供一个翻译器(详细信息请参见下面的链接!),但不要用JSON细节“黑客化”内容!这些几乎是完全正交的方面
    • 为JSON编写一个自己的读写器,应该可以很容易地从Boost版本中进行改编
    优点:

    • 就JSON特定的细节而言,不需要黑客来影响属性树
    • 除了您自己的新类型(变体转换器)的专门化之外,对Boost库及其名称空间没有污染
    • 类型比自定义的基于字符串的属性树方法更安全
    • 对于树的非频繁序列化的许多运行时场景,应该更快
    缺点:

    • 对于行为的一个相当小的细节,需要一些努力
    • 在编译方面可能会慢一点
    • 对于频繁序列化和树的微小更改的运行时场景,可能会稍微慢一点(当然可以优化)
    • 将json读回树中是一种值得怀疑的哲学工作,以确保所用类型之间尽可能多的对称性(出于许多目的,而不是学术问题)
    如需有关详细信息,请参阅


    你可以很容易地将其适应于不同的用法。

    +1知道现在没有干净的解决方案,并且需要一个乱码。如果双引号没有转义,那么如果这个引号恰好在你的字符串中,你可能会遇到问题。最后,它是否也适用于写和读。或者是只写?@alfC这真的很旧。我很抱歉不确定它是否仍然有效。这是很久以前的事了,但我认为它是读写的。事实上,上面的代码(带有未触及的标题)仍然有效。如果结果是可转换的(
    lexical\u cast
    ed),可能只是打印不带引号的字符串的问题这可以通过为
    property\u tree
    重载
    write/read\u json\u helper
    来完成,而不是修改核心标题。我认为这是一个非常轻描淡写的说法。更正确的说法是property\u tree实际上不支持json。不幸的是,我发现了这一点。有一个这里有比“严格打字”更多的限制。这对我的一个项目很有帮助。谢谢:)
    elem2.put<std::string>("key2", "asdf", my_id_translator<std::string>());
    
    #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;
    }
    
    {
        "path1":
        {
            "path2":
            [
                {
                    "int": 10,
                    "bool": true
                },
                {
                    "double": 2.2,
                    "string": "some string"
                }
            ]
        }
    }
    
    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);
    }
    
    #include <string>
    #include <regex>
    #include <boost/property_tree/json_parser.hpp>
    
    namespace bpt = boost::property_tree;
    typedef bpt::ptree JSON;
    namespace boost { namespace property_tree {
        inline void write_jsonEx(const std::string & path, const JSON & ptree)
        {
            std::ostringstream oss;
            bpt::write_json(oss, ptree);
            std::regex reg("\\\"([0-9]+\\.{0,1}[0-9]*)\\\"");
            std::string result = std::regex_replace(oss.str(), reg, "$1");
    
            std::ofstream file;
            file.open(path);
            file << result;
            file.close();
        }
    } }