boost生成和解析json

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/byxdaz/article/details/82226750

一、boost生成和解析json
解析Json的方法有很多,也有不少的第三方开源工具。比如boost json、jsoncpp库。这里仅介绍其中的一种,用Bosst解析。Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的发动机之一。 Boost库由C++标准委员会库工作组成员发起,其中有些内容有望成为下一代C++标准库内容。在C++社区中影响甚大,是不折不扣的“准”标准库。Boost由于其对跨平台的强调,对标准C++的强调,与编写平台无关。大部分boost库功能的使用只需包括相应头文件即可,少数(如正则表达式库,文件系统库等)需要链接库。
property_tree可以解析xml,json,ini,info等格式的数据,用property_tree解析这几种格式使用方法很相似。
解析json很简单,命名空间为boost::property_tree,reson_json函数将文件流、字符串解析到ptree,write_json将ptree输出为字符串或文件流。其余的都是对ptree的操作。
ptree中put和add区别,add是添加一个元素,名称重复也添加;put也添加一个元素,名称重复的被新值覆盖。
ptree中put_child和add_child区别,也是与上面同理。put_child和add_child是添加一个子对象。

要解析Json,需要包括头文件。

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/date_time.hpp>
#include <boost/foreach.hpp>
//生成
	boost::property_tree::ptree pt_allitem;
	unsigned char ucAttahId = 1;
	boost::property_tree::ptree pt_item, pt_subitem;
	pt_item.put("attachid", ucAttahId);
	pt_subitem.put("mileage", 100.89);
	pt_item.put_child("attachcontent", pt_subitem);
	pt_allitem.add_child("attach",pt_item);
	pt_allitem.add_child("attach", pt_item);
	pt_allitem.add_child("attach", pt_item);
	std::stringstream ss;
	boost::property_tree::write_json(ss, pt_allitem);
	std::string strContent = ss.str();
	
//解析
std::string strResponse = ""//需要解析的json字符串
boost::property_tree::ptree pt;
std::stringstream sstream(strResponse);
boost::property_tree::json_parser::read_json(sstream, pt);
int nErrorCode = pt.get<int>("errorCode");
boost::property_tree::ptree pChild_Payload;
pChild_Payload = pt.get_child("payload");
nTotalPageCount = pChild_Payload.get<int>("totalPage");
nCurrentPage = pChild_Payload.get<int>("curPage");
boost::property_tree::ptree pChild_ModelList = pChild_Payload.get_child("modelList");
//遍历数据
BOOST_FOREACH(boost::property_tree::ptree::value_type &v, pChild_ModelList)
{
 boost::property_tree::ptree p = v.second;
 boost::property_tree::ptree ptDevice = p.get_child("device");
}
					
遍历读取到map
ptree m_pt;
string strAttrName;
BOOST_FOREACH(ptree::value_type &v1, m_pt.get_child(L"root"))
{
    if (v1.first == L"Item")
    {
          strAttrName=v1.second.get<string>(L"<xmlattr>.name");
    }

}

删除节点
删除也一样,遍历之后删除节点。
ptree& persons = pt.get_child("root.persons");
for(auto it = persons.begin(); it != persons.end();) 
{
   if(it->second.get<string>("name") == "dad")
        it = persons.erase(it);
    else
        ++it;
}

修改值
改也很简单,遍历出所要改的值在节点,直接赋值然后再写回去就行了。
iter2->second.put_value(value);

抛出异常
property_tree的异常分两种,一种是路径错误,一种是值错误很好判断,异常直接告诉你哪个属性等有问题
try
    {    
        .......
    }
    catch (boost::property_tree::ptree_bad_path& e)
    {
        m_error = e.what();
        return false;
    }
    catch (boost::property_tree::ptree_bad_data& e)
    {
        m_error =e.what();
        return false;
    }

二、boost json使用过程中需要注意的问题
1、boost json不支持空数组,不支持空数组的生成;但可以解析空数组json字符串。
     如何生成空数组json字符串,折衷方法通过boost json先生成带名称的的数组。再通过截取[]前后字符串。

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/foreach.hpp>
#include "boost/typeof/typeof.hpp"
#include "boost/optional.hpp"
#include <list>
#include <boost/algorithm/string.hpp>

//带名字数组jons字符串转换成空数组json字符串
bool ConvertWithNameJsonArrayStringToWithoutNameJsonArrayString(std::string strWithNameJson, std::string & strWithoutNameJson)
{
	if (strWithNameJson.size() == 0)
	{
		return false;
	}
	strWithoutNameJson = strWithNameJson;
	boost::iterator_range<std::string::iterator> result = boost::algorithm::find_first(strWithoutNameJson, "[");
	if (!result.empty())
	{
		std::string strTemp = strWithoutNameJson.substr(result.begin() - strWithoutNameJson.begin());
		strWithoutNameJson = strTemp;
		result = boost::algorithm::find_last(strWithoutNameJson, "]");
		//result = boost::algorithm::ifind_first(strWithoutNameJson, "]");
		if (!result.empty())
		{
			strTemp = strWithoutNameJson.substr(0, (result.begin() - strWithoutNameJson.begin() + 1));
			strWithoutNameJson = strTemp;
		}
	}
	return true;
}

//示例代码
boost::property_tree::ptree ptRoot;
	boost::property_tree::ptree ptAllGps;
	boost::property_tree::ptree ptGps;
	for (int n = 0; n < 10; n++)
	{
		ptGps.put("deviceid", "1234567");
		ptGps.put("alarmFlag", 0);
		ptGps.put("deviceStatus", 1);
		ptGps.put("lng", 111.0990909);
		ptGps.put("lat", 28.1112323);
		ptGps.put("speed", 80.0);
		ptGps.put("direction", 0);
		ptGps.put("gpsTime", "2018-08-28 12:12:11");
		//insert
		ptAllGps.push_back(make_pair("", ptGps));
	}
	ptRoot.add_child("allgps", ptAllGps);
	std::stringstream sstream;
	boost::property_tree::write_json(sstream, ptRoot);
	std::string strRequestParams = sstream.str();
	std::string strWithoutJsonArray = "";
	ConvertWithNameJsonArrayStringToWithoutNameJsonArrayString(strRequestParams, strWithoutJsonArray);

	boost::property_tree::ptree ptRootAllGps;
	std::stringstream sstream1(strWithoutJsonArray);
	boost::property_tree::json_parser::read_json(sstream1, ptRootAllGps);
	int kkk = 0;
	BOOST_FOREACH(boost::property_tree::ptree::value_type &v, ptRootAllGps)
	{
		boost::property_tree::ptree p = v.second;
		std::string strDeviceId = p.get<std::string>("deviceid");
		std::string strTime = p.get<std::string>("gpsTime");
		double fLng = p.get<double>("lng");
		kkk++;
	}

2、空的字符串字段转换为数字会抛异常。
3、boost json线程不安全及其解决办法
原因是 boost json parser中用到ptree底层依赖boost::spirit,是线程不安全的,从而导致程序出core。解决方案:
在任何引入头文件的地方加上如下宏
 

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

4、put int,double都保存为string而不能保存int,double的解决方法
https://stackoverflow.com/questions/2855741/why-boost-property-tree-write-json-saves-everything-as-string-is-it-possible-to

猜你喜欢

转载自blog.csdn.net/byxdaz/article/details/82226750