Boost::property tree 를 이용한 json 스크립트 파싱

jjuiddong
이동: 둘러보기, 찾기

목차

여러개의 속성을 가진 child 정보를 가져오는 방법

	"property" : [
		{
			"symbolname" : "CLobbyServer#1"
		},
		{
			"symbolname" : "CLobbyServer#1"
		}
	]

boost::property_tree 를 이용한 json 스크립트 파싱

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

using boost::property_tree::ptree;
ptree props;
boost::property_tree::read_json("filename", props);
ptree &children = props.get_child("property");
BOOST_FOREACH(ptree::value_type &vt, children)
{
	const string name = vt.second.get<string>("symbolname");
	... 
}

일반적인 JSon 파싱

{
   "attribute1" : "100"
   ,"attribute2" : "0 0 100 100"
   ,"attribute3" : "0 0 100 100"
   ,"attribute4" : "200"
   ,"attribute5" : "5"
   	
   , "attribute6" :
    [
   	  {
   		  "sub-attr1" : "data1"
   		  ,"sub-attr2" : "data2"
   	  }

   	  ,{
   		  "sub-attr1" : "data3"
   		  ,"sub-attr2" : "data4"
   	  }
    ]
}

JSon Parsing Sample Code

bool cConfig::Read(const char *fileName)
{
	using boost::property_tree::ptree;

	Clear();

	try
	{
		ptree props;
		boost::property_tree::read_json(fileName, props);

		m_attribute1 = props.get<int>("attribute1", 100);
		m_attribute2 = props.get<string>("attribute2", "0 0 0 0");
		m_attribute3 = props.get<string>("attribute3", "0 0 0 0");
		m_attribute4 = props.get<int>("attribute4", 0);
		m_attribute5 = props.get<int>("attribute5", 5);		

		auto &children = props.get_child("attribute6");
		for (auto &vt : children)
		{
			string subAttr1 = vt.second.get<string>("sub-attr1", "");
			string subAttr2 = vt.second.get<string>("sub-attr2", "");
		}
	}
	catch (std::exception&e)
	{
		string err = e.what();
		return false;
	}
	return true;
}

Array 파싱

"pos" : [1, 2, 3],
"scale" : [1, 2, 3],
"rot" : [1, 2, 3, 4],
"widths" : [1, 2, 3, 4, 5, 6],
template <class T, size_t MAX>
bool GetArray(boost::property_tree::ptree &ptree, const string &key, OUT T out[])
{
	int idx = 0;
	auto it = ptree.get_child(key);
	for (auto &kv : it)
	{
		out[idx++] = kv.second.get<T>("");
		if (idx >= MAX)
			break;
	}
	return true;
}

template <class T>
bool GetVector(boost::property_tree::ptree &ptree, const string &key , OUT vector<T> &out)
{
	auto it = ptree.get_child(key);
	for (auto &kv : it)
		out.push_back(kv.second.get<T>(""));
	return true;
}
 
// json string parsing and return vec3
// "key" : [1, 2, 3]
Vector3 GetVector3(boost::property_tree::ptree &ptree, const string &key)
{
	float ar[3];
	GetArray<float, 3>(ptree, key, ar);
	return Vector3(ar[0], ar[1], ar[2]);
}

// json string parsing and return vec4
// "key" : [1, 2, 3, 4]
Vector4 GetVector4(boost::property_tree::ptree &ptree, const string &key)
{
	float ar[4];
	GetArray<float, 4>(ptree, key, ar);
	return Vector4(ar[0], ar[1], ar[2], ar[3]);
}

Vector3 pos = GetVector3(props, "pos");
Vector3 scale = GetVector3(props, "scale");
Vector4 rot = GetVector4(props, "rot");
vector<float> widths;
GetVector<float>(props, "widths", widths);


다른방식의 json 파싱

json 은 key, value 값으로 구성된 스크립트지만, 다음처럼 value값이 없이도 사용할 수 있다.

"collapse" : [
	"basic::s2c",  
	"login::s2c"
]

이 스크립트의 정보를 가져오는 방법은 다음과 같다. (이 예제의 특징은 key value 만 있고, data value는 없다는 점이다.)

ptree &collapse = g_Props.get_child("collapse");
BOOST_FOREACH(auto &child, collapse)
{
	if ("basic::s2c" == child.second.data())
		return true;
}

property_tree find() 로 내부 데이타 얻는법

using boost::property_tree::ptree;
ptree props;
boost::property_tree::read_json(fileName.c_str(), props);
ptree &children = props.get_child("extract");
BOOST_FOREACH(auto &vt, children)
{
	ptree::assoc_iterator fit = vt.second.find("field");
	if (vt.second.not_found() != fit)
	{
		ptree &child_field = vt.second.get_child("field");
		BOOST_FOREACH(auto &v, child_field)
		{
			Jjuiddong (토론)
		}
	}
}

boost::property_tree 데이타 저장

  • 이미 존재하는 scale 키 에 sens 값을 업데이트 한다.
try
{
	// boost property tree
	using boost::property_tree::ptree;
	using std::string;
	ptree props;
	boost::property_tree::read_json(fileName, props);
 
	props.put<float>("scale", sens);

	boost::property_tree::write_json(fileName + "1", props);
}
catch (std::exception&e)
{
	::AfxMessageBox(CString(L"Error!!\n") + str2wstr(e.what()).c_str());
	return false;
}


boost::property_tree 데이타 구성

ptree pt;
ptree children;
ptree child1, child2, child3;

child1.put("childkeyA", 1);
child1.put("childkeyB", 2);

child2.put("childkeyA", 3);
child2.put("childkeyB", 4);

child3.put("childkeyA", 5);
child3.put("childkeyB", 6);

children.push_back(std::make_pair("", child1));
children.push_back(std::make_pair("", child2));
children.push_back(std::make_pair("", child3));

pt.put("testkey", "testvalue");
pt.add_child("MyArray", children);

write_json("test2.json", pt);
{
    "testkey": "testvalue",
    "MyArray":
    [
        {
            "childkeyA": "1",
            "childkeyB": "2"
        },
        {
            "childkeyA": "3",
            "childkeyB": "4"
        },
        {
            "childkeyA": "5",
            "childkeyB": "6"
        }
    ]
}


boost::property_tree 데이타 구성2

https://stackoverflow.com/questions/2114466/creating-json-arrays-in-boost-using-property-trees

ptree pt;
ptree children;
ptree child1, child2, child3;

child1.put("", 1);
child2.put("", 2);
child2.put("", 3);

children.push_back(std::make_pair("", child1));
children.push_back(std::make_pair("", child2));
children.push_back(std::make_pair("", child3));

pt.add_child("MyArray", children);

write_json("test2.json", pt);
{
    "MyArray":
    [
        "1",
        "2",
        "3"
    ]
}

boost::property_tree 데이타 읽기와 저장

  • Source JSon format
{
    "point cloud" : [
        {
            "name" : "name 1",
            "pos" : "1 2 3",
            "description" : "memo 1"
        },
        {
            "name" : "name 2",
            "pos" : "1 2 3",
            "description" : "memo 2"
        }
    ]
}
  • Read JSon file c++
try
{
	ptree props;
	boost::property_tree::read_json(fileName.c_str(), props);

	// parse point cloud
	ptree::assoc_iterator itor = props.find("point cloud");
	if (props.not_found() != itor)
	{
		ptree &child_field = props.get_child("point cloud");
		for (ptree::value_type &vt : child_field)
		{
			sPCData *pc = new sPCData;
			pc->name = vt.second.get<string>("name");
			const string posStr = vt.second.get<string>("pos");
			vector<string> toks;
			common::tokenizer(posStr, " ", "", toks);
			if (toks.size() >= 3)
			{
				pc->pos = Vector3(
					(float)atof(toks[0].c_str())
					, (float)atof(toks[1].c_str())
					, (float)atof(toks[2].c_str()));
			}
			pc->desc = vt.second.get<string>("description");
			m_pcDatas.push_back(pc);
		}
	}
}
catch (std::exception &e)
{
	Str128 msg;
	msg.Format("Read Error!!, Point Cloud Data File [ %s ]\n%s"
		, fileName.c_str(), e.what());
	MessageBoxA(NULL, msg.c_str(), "ERROR", MB_OK);
	return false;
}
  • Write JSon file c++
try
{
	ptree props;

	ptree pcs;
	for (auto &pc : m_pcDatas)
	{
		ptree z;
		z.put("name", pc->name.c_str());

		Str128 text;
		text.Format("%f %f %f", pc->pos.x, pc->pos.y, pc->pos.z);
		z.put("pos", text.c_str());
		z.put("description", pc->desc.c_str());

		pcs.push_back(std::make_pair("", z));
	}

	props.add_child("point cloud", pcs);
	boost::property_tree::write_json(fileName.c_str(), props);
}
catch (std::exception &e)
{
	Str128 msg;
	msg.Format("Write Error!!, Point Cloud File [ %s ]\n%s"
		, fileName.c_str(), e.what());
	MessageBoxA(NULL, msg.c_str(), "ERROR", MB_OK);
	return false;
}
개인 도구
이름공간

변수
행위
둘러보기
도구모음