C++ 轉換成 JSON
經常有朋友問我如何將C++對象轉換成JSON格式字符串。我的回答通常是CppCMS中的json::value. 我也寫過一篇文章介紹該技術。
但是最近有些不同的想法。因為用到一個vector<shared_ptr<> > 數據結構,json::value不支持這個模板特化。同時也發現json::value的設計思想是將所有的c++對象存儲在std::map中,然后再導出為json字符串。但是在我開發的和看到的很多web service開發中,將對象轉換成json字符串,是非常頻繁的。在esri,對象非常多,json格式巨大。如果每次都緩存到map中,顯然過多的copy,內存和cpu都消耗過大。
我的一貫用法就是用流來拼接字符串。這種方法又有點傻。受json::value的設計采用模板特化和偏特化的啟發。我自己也寫了一個簡單的jsoner類。方便了自己開發,現在拿出來。看看能不能方便別人。
先看調用代碼:
vector<string> emails = user_manager::get_emails(user_id); content.user_emails = jsoner<vector<string> >::to_json("emails", emails); shared_ptr<displays> ds = user_manager::find_displays(user_id); content.user_displays_addresses = jsoner<displays>::to_json("displays", *ds);第一個例子:
第一代碼從mongodb中讀取用戶所有的email地址,放到vector<string>容器中。第二行代碼將之導出為固定格式的json字符串。這是第一個例子,簡單但很常用。cppcms::json::value不支持,轉換會失敗。
第二個例子:
第三行代碼找到用戶所有擁有的設備(復數),displays內部擁有一個vector<shared_ptr<display> >成員變量,display就是一個顯示設備,擁有一些屬性。這個例子比較復雜,但是也很常用。良好的封裝經常用復數類包裝,將底層容器的類型對外部屏蔽,這里你不知道我用的是vector,以后我還可以換成list。
為了支持上面的調用代碼,我的jsoner類設計了三個模板重載形式。
#ifndef __JSON_HELPER_H #define __JSON_HELPER_H #include <time.h> #include <string> #include <vector> #include <sstream> #include <boost/shared_ptr.hpp> template<typename T> class jsoner { public: static std::string to_json (std::string const& name, T const& value) { std::stringstream stream; stream << "{\"" << name << "\":"; stream << value.to_json(); stream << "}"; return stream.str(); } }; template<> class jsoner<std::vector<std::string> > { public: static std::string to_json (std::string const& name, std::vector<std::string> const & value) { std::vector<std::string>::const_iterator itor, last = value.end(); std::stringstream stream; stream << "{\"" << name << "\":["; int i = 0; for (itor = value.begin(); itor != last; ++itor) { stream << "{"; stream << "\"index\":" << "\"" << i << "\","; stream << "\"value\":" << "\"" << *itor << "\""; stream << "}"; if(itor != last -1) { stream << ","; } ++i; } stream << "]}"; return stream.str(); } }; template<typename T> class jsoner<std::vector<boost::shared_ptr<T> > > { public: static std::string to_json (std::string const& name, std::vector<boost::shared_ptr<T> > const & value) { typename std::vector<boost::shared_ptr<T> >::const_iterator itor, last = value.end(); std::stringstream stream; stream << "{\"" << name << "\":["; int i = 0; for (itor = value.begin(); itor != last; ++itor) { stream << "{"; stream << "\"index\":" << "\"" << i << "\","; stream << "\"value\":" << (*itor)->to_json(); stream << "}"; if(itor != last -1) { stream << ","; } ++i; } stream << "]}"; return stream.str(); } }; #endif
第一種形式是最普通的,要求T類型必須擁有to_json成員函數。
第二種形式用于支持vector<string>,是模板特化。
第三種形式也是一種特化,但是支持vector<shared_ptr<T>>參數。
在我剛才的第二個例子調用代碼中,找到的是第一種形式用于displays,displays的to_json函數代碼如下:
string displays::to_json() const { return jsoner<vector<shared_ptr<display> > >::to_json("addresses", values_); }它內部調用了第三種形式的特化。而這種形式又要求display類擁有成員函數to_json。
In short,如果你自己的類想要使用這幾個模板,都必須實現自己的to_json函數。
參考這種思路,可以擴充到自己需要的stl容器,比如list等。
轉自:http://blog.csdn.net/sheismylife/article/details/7958470