为什么Boost属性树write_json会将所有内容保存为字符串?有可能改变吗?
我尝试使用boost属性树write_json进行序列化,它将所有内容保存为字符串,并不是因为数据错误,而是每次都需要显式转换它们,我希望在其他地方使用它们。(如Python或其他C++ JSON(非Boost)库) 下面是一些示例代码,以及根据区域设置得到的代码:为什么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::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
中的以下行:
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();
}
} }