Boost 속성 트리 write_json이 모든 것을 문자열로 저장하는 이유는 무엇입니까?그것을 변경할 수 있습니까?
boost property tree write_json을 사용하여 시리얼화하려고 합니다.모든 것을 문자열로 저장합니다.데이터가 잘못된 것은 아니지만 매번 명시적으로 캐스팅해야 하기 때문에 다른 장소에서 사용하고 싶습니다.(python 또는 기타 C++ json(비부스트) 라이브러리와 유사)
다음은 샘플 코드와 로케일에 따라 표시되는 코드입니다.
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
function (파일을 복사한 파일,json_parser.hpp
그리고.json_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% 준수하지 않음을 확인합니다.설명을 보려면 다음 링크를 확인하십시오.JSON 타입을 보존하는 ptree 배리언트를 작성하는 것은 장래의 계획이지만, 아직 멀었다.
이 문제를 해결하기 위해 다른 기능을 유틸리티에 추가했습니다.
#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();
}
} }
도움이 됐으면 좋겠다.
가장 간단하고 깔끔한 솔루션은 플레이스 홀더를 사용하여 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":"get Orders", 인수:{"pending Only" : true , someIntValue " : 15}
부스트 라이브러리에는 typedef basic_ptree <std::string, std::string> ptree가 있기 때문에 부스트는 항상 각 값을 문자열로 시리얼화하고 모든 값을 동등한 문자열로 해석합니다.
출력된 JSON에서 시리얼라이저는 어떤 종류의 .toString() 메서드를 사용하여 모든 것을 문자열로 시리얼화하는 것이 분명합니다.즉, 각 멤버의 유형을 인식하지 못하고 모든 것을 " "에 포함시킵니다.
이 문제에 대한 자세한 내용은 속성 트리를 사용한 부스트의 JSON 어레이 작성을 참조하십시오.
스트링에 커스텀 번역기를 명시적으로 필요로 하는 모든 솔루션은 때때로 잊어버리기 쉽기 때문에 오류가 발생하기 쉬운 것 같습니다.속성 트리의 put 메서드가 이를 암묵적으로 처리하기 위해 상속을 통한 오버로드 방법이 있으면 좋겠지만 템플릿이기 때문에 강력한 방법으로는 가능하지 않으며 트리의 모든 메서드에 대해 완전한 공분산을 보장해야 합니다.또, 가능한 한 회피책으로서 부스트 라이브러리의 내용을 변경하는 것은 피해야 합니다.
지금까지 발견된 해킹이 없는 가장 견고한 방법은 (C++11 이후)입니다.
- 부스트 트리를 사용하다
<KeyType, std::variant<yourTypes>>
- 사용하시는 번역자(자세한 내용은 아래 링크 참조)를 제공하되, JSON 고유의 관점에서 내용을 "해킹"하지는 마십시오.이것들은 거의 직교하는 양상입니다!
- JSON용 독자 및 라이터를 작성합니다.Boost에서 쉽게 적응할 수 있어야 합니다.
장점:
- JSON 관련 세부 정보와 관련하여 속성 트리에 영향을 주는 데 해크가 필요하지 않습니다.
- Boost 라이브러리와 그 네임스페이스는 새로운 유형의 전문화(변종 번역자)를 제외하고 오염되지 않습니다.
- 사용자 지정 문자열 기반 속성 트리 접근 방식보다 안전한 유형
- 많은 런타임 시나리오에서 트리의 비패키지 시리얼라이제이션이 더 빠를 수 있습니다.
단점:
- 행동의 아주 작은 디테일을 위해 약간의 노력이 필요하다
- 컴파일에 있어서 조금 느릴 수 있습니다.
- 트리의 시리얼화와 사소한 변경이 빈번한 런타임 시나리오에서는 조금 느릴 수 있습니다(확실히 최적화할 수 있습니다).
- json을 트리로 다시 읽는 것은 사용된 유형 간에 가능한 한 많은 대칭을 보장하기 위한 일종의 철학적인 작업이다(다양한 목적을 위해 오히려 학문적인 문제).
예를 들어 자세한 내용은 를 참조하십시오.
http://marko-editor.com/articles/property_tree_store_anything/
이것은, 다양한 용도에 맞추어 간단하게 조정할 수 있습니다.
언급URL : https://stackoverflow.com/questions/2855741/why-does-boost-property-tree-write-json-save-everything-as-string-is-it-possibl
'programing' 카테고리의 다른 글
매트릭스 치수를 유지하면서 numpy 어레이를 시리얼화하려면 어떻게 해야 합니까? (0) | 2023.04.03 |
---|---|
대응 | 페이지 갱신 검출 방법 (F5) (0) | 2023.04.03 |
WooCommerce 관리자 주문 대시보드에서 고객 암호 업데이트 (0) | 2023.04.03 |
현재 상태와 일치하도록 AJAX 앱의 주소 표시줄 URL 수정 (0) | 2023.04.03 |
노드 + 익스프레스 + 옥에서 클라이언트에 개체를 전달하고 있습니까? (0) | 2023.04.03 |