C++ 轉換成 JSON

jopen 12年前發布 | 34K 次閱讀 JSON C/C++開發

經常有朋友問我如何將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

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!