programing

Boost 속성 트리 write_json이 모든 것을 문자열로 저장하는 이유는 무엇입니까?그것을 변경할 수 있습니까?

powerit 2023. 4. 3. 21:47
반응형

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_jsonfunction (파일을 복사한 파일,json_parser.hpp그리고.json_parser_write.hpp내 프로젝트에 적용) 및 다음 행을 수정했습니다.json_parser_write.hpp:

  1. 37행 코멘트 - 따옴표 '의 이스케이프
  2. 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

반응형