2013年5月23日 星期四

C++ 處理 JSON (使用 JsonCpp)

環境:Visual Studio Express 2012

JsonCpp:http://jsoncpp.sourceforge.net/
下載:http://sourceforge.net/projects/jsoncpp/files/

 使用 JsonCpp 時,先將 JsonCpp 編譯成 lib 檔。
  1. 將下載的 JsonCpp 解壓縮,我解壓縮到 D:\jsoncpp-src-0.5.0
  2. 啟動 VS2012,「檔案」->「開啟專案」,
    到 D:\jsoncpp-src-0.5.0\makefiles\vs71 開啟 jsoncpp.sln,
    VS2012 會進行單向升級,以便 VS2012能夠開啟。
  3. 編譯時若出錯,依下列步驟修改。(以下我是編譯成 Release 版)
  4. 若出現以下警告訊息
    [錯誤清單]訊息
    警告    1    warning MSB8012: TargetPath(D:\jsoncpp-src-0.5.0\makefiles\vs71\../../build/vs71/release/lib_json\lib_json.lib) does not match the Library's OutputFile property value (D:\jsoncpp-src-0.5.0\build\vs71\release\lib_json\json_vc71_libmt.lib). This may cause your project to build incorrectly. To correct this, please make sure that $(OutDir), $(TargetName) and $(TargetExt) property values match the value specified in %(Lib.OutputFile).    C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V110\Microsoft.CppBuild.targets    1299    5    lib_json
    警告    2    warning MSB8012: TargetName(lib_json) does not match the Library's OutputFile property value (json_vc71_libmt). This may cause your project to build incorrectly. To correct this, please make sure that $(OutDir), $(TargetName) and $(TargetExt) property values match the value specified in %(Lib.OutputFile).    C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V110\Microsoft.CppBuild.targets    1301    5    lib_json

    [輸出]訊息
    1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V110\Microsoft.CppBuild.targets(1299,5): warning MSB8012: TargetPath(D:\jsoncpp-src-0.5.0\makefiles\vs71\../../build/vs71/release/lib_json\lib_json.lib) does not match the Library's OutputFile property value (D:\jsoncpp-src-0.5.0\build\vs71\release\lib_json\json_vc71_libmt.lib). This may cause your project to build incorrectly. To correct this, please make sure that $(OutDir), $(TargetName) and $(TargetExt) property values match the value specified in %(Lib.OutputFile).

    1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V110\Microsoft.CppBuild.targets(1301,5): warning MSB8012: TargetName(lib_json) does not match the Library's OutputFile property value (json_vc71_libmt). This may cause your project to build incorrectly. To correct this, please make sure that $(OutDir), $(TargetName) and $(TargetExt) property values match the value specified in %(Lib.OutputFile).

    解決方式:
    在「lib_json」專案上按「右鍵」->「屬性」->「組態屬性」->「管理員」->「一般」->「輸出檔」->原本是「$(OutDir)json_vc71_libmt.lib」->改選「從父代或專案預設值繼承」。
    如下圖:

  5. 若出現以下錯誤訊息
    [錯誤清單]訊息
    錯誤    1    error C1083: 無法開啟編譯器中產生的檔案: '../../build/vs71/release/lib_json\json_value.asm': Permission denied    D:\jsoncpp-src-0.5.0\src\lib_json\json_value.cpp    1    1    test_lib_json
    錯誤    2    error LNK1257: 無法產生程式碼    D:\jsoncpp-src-0.5.0\makefiles\vs71\LINK    test_lib_json

    [輸出]訊息
    3>D:\jsoncpp-src-0.5.0\src\lib_json\json_value.cpp : fatal error C1083: 無法開啟編譯器中產生的檔案: '../../build/vs71/release/lib_json\json_value.asm': Permission denied
    3>LINK : fatal error LNK1257: 無法產生程式碼

    解決方式:
    在「lib_json」專案上按「右鍵」->「屬性」->「組態屬性」->「C/C++」->「輸出檔」->「組合語言輸出」->原本是「具原始程式碼的組譯碼 (/FAs)」->改選「未列出」
    如下圖:
  6. 修改到這邊,應該可以正常編譯了。
    注意,編譯後得到的是 Release 版 、MT的,我下載的 JsonCpp 預設是編譯成 MT,
    若要改成 MD,可如下修改
    在專案上按「右鍵」->「屬性」->「組態屬性」->「C/C++」->「程式碼產生」->「執行階段程式庫」->改成「多執行緒 DLL (/MD)」
    (我是將「jsontest」、「lib_json」、「lib_json」都同時改為 MT,或同時改為 MD)
    如下圖為修改「lib_json」專案
  7. 編譯完,產生的 D:\jsoncpp-src-0.5.0\build\vs71\release\lib_json\lib_json.lib 這個檔,即是我們要的檔
    (若忽略前面第4點的警告訊息,則不是產生 lib_json.lib,而是 json_vc71_libmt.lib)
  8. 以上是產生 release 版本的 lib。
    若工作的專案,使用這個 release 版本的 lib,但是在編譯時,選 debug 模式,則會產生 _ITERATOR_DEBUG_LEVEL 不符合的錯誤。
    錯 誤    3    error LNK2038: 偵測到 '_ITERATOR_DEBUG_LEVEL' 不符: '0' 值與 '2' 值 (位於 json2.obj) 不符    D:\VStest\json2\json2\lib_json.lib(json_value.obj)    json2
    錯誤    4    error LNK2038: 偵測到 'RuntimeLibrary' 不符: 'MD_DynamicRelease' 值與 'MDd_DynamicDebug' 值 (位於 json2.obj) 不符    D:\VStest\json2\json2\lib_json.lib(json_value.obj)    json2
    錯誤    5    error LNK2038: 偵測到 '_ITERATOR_DEBUG_LEVEL' 不符: '0' 值與 '2' 值 (位於 json2.obj) 不符    D:\VStest\json2\json2\lib_json.lib(json_reader.obj)    json2
    錯誤    6    error LNK2038: 偵測到 'RuntimeLibrary' 不符: 'MD_DynamicRelease' 值與 'MDd_DynamicDebug' 值 (位於 json2.obj) 不符    D:\VStest\json2\json2\lib_json.lib(json_reader.obj)    json2
    錯誤    7    error LNK2038: 偵測到 '_ITERATOR_DEBUG_LEVEL' 不符: '0' 值與 '2' 值 (位於 json2.obj) 不符    D:\VStest\json2\json2\lib_json.lib(json_writer.obj)    json2
    錯誤    8    error LNK2038: 偵測到 'RuntimeLibrary' 不符: 'MD_DynamicRelease' 值與 'MDd_DynamicDebug' 值 (位於 json2.obj) 不符    D:\VStest\json2\json2\lib_json.lib(json_writer.obj)    json2

    解決方式:
    重新在 debug 模式下編譯一個 debug 用的 lib_json.lib
    (執行階段程式庫,則改選 MTd 或 MDd)
    參考:http://stackoverflow.com/questions/4061929/help-with-linker-error-lnk2038
     
  9. 使用時,
    a.將 D:\jsoncpp-src-0.5.0\include\json 資料夾,複製到專案目錄下
    b.將 lib_json.lib 複製到專案目錄下,例如 lib/lib_json.lib
    範例:(注意專案的執行階段程式庫設定(MD、MT、MDd、MTd),須和前面編譯 jsoncpp 的設定一樣 )
    #include "stdafx.h"
    #include "json/json.h"
    #pragma comment(lib,"lib/lib_json.lib")
    #include "string"
    using namespace std;
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        Json::Reader reader;
        Json::Value root;
    
        //解析 JSON:範例1
        string json_str = "{\"aa\":\"test123\",\"bb\":\"test456\"}";
        if(reader.parse(json_str,root,false)){
            cout << "aa:" << root["aa"].asString() <<endl; //aa:test123
            cout << "bb:" << root["bb"].asString() <<endl; //bb:test456
        }
    
        //解析 JSON:範例2
        string  json_str2 = "{\"aa\":\"aa99\",\"arr\":[{\"m1\":\"v1\"},{\"m2\":\"v2\"}]}";
        if (reader.parse(json_str2, root))
        {   
            string str = root["aa"].asString();
            cout << str << std::endl; //aa99
    
            Json::Value arrayObj = root["arr"];
            for (unsigned int i = 0; i < arrayObj.size(); i++)
            {   
                if(arrayObj[i].isMember("m1")) str = arrayObj[i]["m1"].asString();//v1
                if(arrayObj[i].isMember("m2")) str = arrayObj[i]["m2"].asString();//v2
                cout << str << endl;   
            }   
        }
    
    
    
        //序列化為 JSON:範例
        Json::Value myroot;
        Json::Value myarr;
        Json::Value myitem;
        myitem["aa"] = 123;
        myitem["bb"] = "b456";
    
        myarr.append(myitem);
    
        myroot["test"] = "vv";
        myroot["arr"] = myarr;
    
        //輸出方式 1
        string str = myroot.toStyledString(); //輸出帶格式的JSON字串
        cout << str;
        /* 輸出結果
        {
           "arr" : [
              {
                 "aa" : 123,
                 "bb" : "b456"
              }
           ],
           "test" : "vv"
        }
        */
        
        //輸出方式 2
        Json::FastWriter writer;  
        string str2 = writer.write(myroot);//輸出不帶格式的JSON字串
        cout << str2; //{"arr":[{"aa":123,"bb":"b456"}],"test":"vv"}
        getchar();
        return 0;
    }
    

1 則留言: