boost - json - 为什么Boost属性树会将所有内容保存为字符串 有没有可能改变?

我正在尝试使用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();



my_string_to_send_somewhere_else就是这样的:


{


"path1" :


 {


"path2" :


 [


 {


"key0" :"0",


"key1" :"true"


 },


 {


"key2" :"2.2",


"key3" :"3.3"


 }


 ]


 }


}



是否将它们保存为值,如: "key1":true"key2":2.2

时间:

我编写了自己的write_json函数(简单地将文件,json_parser.hppjson_parser_write.hpp复制到我的项目中),并且在json_parser_write.hpp中修改了以下行:

  • 注释行37转义引号\'"\'
  • 更改了行76 —因此它不再添加引号: stream << Ch(\'"\') << data << Ch(\'"\'); ==> stream << data;

然后,除了字符串之外,值将被正确保存,因此我为它编写了自定义转换器:


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


};



使用以下方法保存了字符串:


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"


 }


 ]


 }


}



Boost确认与JSON标准没有100%的一致性。查看以下链接以查看其说明: Making a ptree variant that preserves JSON types is a future plan, but far off!

最简单的解决方案是生成带占位符的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);


}



结果是

“command”:“getorders”,“arguments”:“PendingOnly”:true,“someIntValue”:15_,

我最终添加了另一个函数来解决这个问题:


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


 }


} }



希望它能帮上忙。

...