CppCMS的編譯和使用
請參考我的相關文章。
將C++對象轉換成JSON字串
假定有一個類response,兩個欄位,一個是status,0代表正確。其他代表錯誤。另一個是message欄位,表示操作結果的具體資訊。代碼如下:
class response {public: //0 is ok //other values are wrong int status; string message;};
現在需要將response對象的資料轉換成JSON格式字串。還需要寫一個模板類來,代碼如下:
namespace cppcms { namespace json { template<> struct traits<response> { static void set(value &v, response const& in) { v.set("status", in.status); v.set("message", in.message); } }; }}
好,現在編寫調用代碼,並查看運行結果。
#include <cppcms/json.h>...int main(int argc, char** argv) { response r1; r1.status=0; r1.message="ok"; cout<< cppcms::json::value(r1)<<endl; response r2; r2.status=1; r2.message="unknown error"; cout<< cppcms::json::value(r2)<<endl; return 0;}
運行結果:
{"message":"ok","status":0}
{"message":"unknown error","status":1}
cppcms::json::value類程式碼分析
之所以很容易就轉換成JSON串,是因為使用了value類。現在來分析一下上面的調用代碼裡面是如何工作的。
1.cppcms::json::value(r1) 建立了匿名對象value,value的建構函式內部調用了set_value方法。參數v此時就是response對象。
template<typename T> value(T const &v) { set_value(v); }
2.set_value方法調用了traits<T>::set(this,v),這個就是前面我們重載的模板方法。
template<typename T> void set_value(T const &v) { traits<T>::set(this,v); }
3.剩下的事情目的很明確了,需要將value對象的屬性按照key,value的形式儲存在map中。最後轉換成JSON字串,然後輸出到流中。Artyom重載了operator<<函數,底層實現函數如下:
std::ostream &operator<<(std::ostream &out,value const &v) { v.save(out); return out; } void value::save(std::ostream &out,int how) const { int tabs=(how & readable) ? 0 : -1; write(out,tabs); } void value::write(std::ostream &out,int tabs) const { std::locale original(out.getloc()); out.imbue(std::locale("C")); try { write_value(out,tabs); } catch(...) { out.imbue(original); throw; } out.imbue(original); } void value::write_value(std::ostream &out,int tabs) const { switch(type()) { case json::is_undefined: throw bad_value_cast("Can't write undefined value to stream"); case json::is_null: out<<"null"; break; case json::is_number: out<<std::setprecision(std::numeric_limits<double>::digits10+1)<<number(); break; case json::is_string: out<<escape(str()); break; case json::is_boolean: out<< (boolean() ? "true" : "false") ; break; case json::is_array: { json::array const &a=array(); unsigned i; indent(out,'[',tabs); for(i=0;i<a.size();) { a[i].write_value(out,tabs); i++; if(i<a.size()) indent(out,',',tabs); } indent(out,']',tabs); } break; case json::is_object: { json::object const &obj=object(); object::const_iterator p,end; p=obj.begin(); end=obj.end(); indent(out,'{',tabs); while(p!=end) { out<<escape(p->first); indent(out,':',tabs); p->second.write_value(out,tabs); ++p; if(p!=end) indent(out,',',tabs); } indent(out,'}',tabs); } break; default: throw bad_value_cast("Unknown type found: internal error"); } }
上面的程式碼封裝含了很多細節,很多都可以獨立成文描述。這裡主要是為了搞明白cppcms::json::value內部的設計原理,便於更好的使用。就暫時追蹤到這裡。
將JSON字串轉換成C++對象
下面的代碼示範了如何將流裡面的JSON串放入value對象,然後通過get方法尋找,"null"是假定找不到的時候的預設值。
stringstream stream; stream << "{\"message\":\"ok\",\"status\":0}"; cppcms::json::value value2; stream >> value2; string m = value2.get("message","null");
也可以用更嚴格的get方法的重載,沒有預設值,如果找不到就會拋出bad_cast異常。
/// /// Get an object of type T from the path \a path. Throws bad_value_cast if such path does not /// exists of conversion can't be done /// template<typename T> T get(std::string const &path) const { return at(path).get_value<T>(); }
我不喜歡寫篇幅很大的文章,本篇主要描述如何使用,順便挖了一下原始碼。後面會陸續深挖CppCMS的原始碼。