개발 라이브러리 & 툴

C++ boost json 구조체와 json 문자열간 변환 예제

하늘흐늘 2021. 11. 21. 13:13
반응형

boost json라이브러리를 사용하면 구조체와 json문자열 간의 상호 변환이 간단합니다. 여기서는 간단한 변환 예를 살펴보며 사용법을 알아보겠습니다. 

우선 아래와 같은 간단한 예로 살펴보겠습니다.

#include <iostream>
#include <string>
#include <boost/json.hpp>

using namespace std;


struct user
{
	int id;
	string name;
	bool  login;
};

void tag_invoke(boost::json::value_from_tag, boost::json::value& jv, user const& u)
{
	jv =
	{
		{"id", u.id},
		{"name", u.name},
		{"login", u.login}
	};
}

user tag_invoke(boost::json::value_to_tag<user>, boost::json::value const& jv)
{
	boost::json::object const& obj = jv.as_object();
	return user
	{
		boost::json::value_to<int>(obj.at("id")),
		boost::json::value_to<string>(obj.at("name")),
		boost::json::value_to<bool>(obj.at("login"))
	};
}

void to_user(boost::json::value const& jv, user& out)
{
	boost::json::object const& obj = jv.as_object();
	
	out.id = boost::json::value_to<int>(obj.at("id"));
	out.name = boost::json::value_to<string>(obj.at("name"));
	out.login = boost::json::value_to<bool>(obj.at("login"));
}


int main(int argc, char* argv[])
{
	user object{ 777, "DevMemo", true };
	
	//부분 #1: 구조체 -> json 문자열
	boost::json::value jv = boost::json::value_from(object);
	string json =  boost::json::serialize(jv);
	cout << json << endl;

	//부분 #2: json 문자열 -> 구조체 
	boost::json::error_code ec;
	boost::json::value jv2 = boost::json::parse(json, ec);

	if (ec.failed())
	{
		cout << ec.message() << endl;
		return -1;
	}

	user from_json(boost::json::value_to<user>(jv2));
	cout << "user: " << from_json.id << ", " << from_json.name << ", " << from_json.login << endl;

	//부분 #3: json 문자열 -> 구조체 방법2 
	user from_json2;
	to_user(jv2, from_json2);
	cout << "user: " << from_json2.id << ", " << from_json2.name << ", " << from_json2.login << endl;

	return 0;
}

해당 소스에 대한 결과는 아래와 같습니다.

{"id":777,"name":"DevMemo","login":true}
user: 777, DevMemo, 1
user: 777, DevMemo, 1

위의 주석 부분을 참고하시며 아래 부분을 설명을 살펴 보겠습니다.

//부분 #1: 구조체 -> json 문자열
boost::json::value_from(object)을 수행하기 위하여 tag_invoke(boost::json::value_from_tag... 부분 함수를 예제처럼 정의하여 주어야 합니다. 여기서 tag_invoke 함수는 구조체를 json::value로 변환하는 역활을 합니다.
json::value 값은 boost::json::serialize 함수를 통하여 json문자열이 됩니다. 주의할점은 이 함수는 문자열을 UTF-8로 별도로 변환하지 않는 관계로 JSON 관련해서 UTF-8을 필요로 할 경우 결과 값을 가지고 별도의 변환을 해주어야 합니다.
참고: boost locale을 이용한 C++에서의 Multi Byte와 UTF8간의 문자열 변환

//부분 #2: json 문자열 -> 구조체 
user from_json(boost::json::value_to<user>(jv2)) 을 수행하기 위하여  tag_invoke(boost::json::value_to_tag...부분 함수를 예제처럼 정의하여 주어야 합니다. 여기서 tag_invoke 함수는 json::value 값을 구조체로 변환하는 역활을 합니다.
boost::json::parse 함수를 통하여 json:value로 변환할 때 파싱하는 json 문자열은 UTF-8로 인코딩되어 있어야 합니다. 영문이나 숫자는 상관없지만 한글과 같은 경우 파싱에러가 납니다. 이 에러는 error_code구조체 인자를 통하여 알 수 있습니다.

//부분 #3: json 문자열 -> 구조체 방법2 
부분 #2에 있는 방법이 boost json라이브러리의 정식 방법인데 소스에서 보이는 것처럼 불필요한 암묵적 복사가 일어나는 것을 알 수 있습니다. JSON이 간단한 경우야 상관 없겠지만 복잡해서 구조체의 용량이 클경우 복사가 있는 정식 방법을 사용하는 것은 일정량의 오버헤드를 야기할 수도 있습니다. 이럴 경우 이 부분의 예제처럼 json::value와 구조체의 변환을 to_user함수와 같이 정의하고 사용하는 것도 좋을 거 같습니다.

 

반응형