1. 程式人生 > >極力推薦一個簡單好用的C++JSON庫

極力推薦一個簡單好用的C++JSON庫

  極力推薦一個簡單好用的C++JSON庫CJsonObject,讓使用json如使用C++原生的結構體那般方便,隨心所欲。CJsonObject是個優秀的C++JSON庫,也許會是你見過的最為簡單易用的C++json庫。CJsonObject的開源地址是https://github.com/Bwar/CJsonObject和https://gitee.com/Bwar/CJsonObject。在開源之初發布的一篇介紹CJsonObject使用的部落格《輕量簡單好用的C++JSON庫CJsonObject》。

  CJsonObject開源一年,沒有刻意推廣,在GitHub上獲得130多star和60多fork,事實上當初把CJsonObject開源並建立一個與cJSON的fork關係(事實上CJsonObject與github上的cJSON沒有任何關係,CJsonObject使用的cJSON是基於SourceForge上版本比較老的cJSON基礎上修改的)是為了多引入一些流量到Bwar傾力打造的另一開源專案Nebula。沒想到,傾力打造並且寫了好幾篇有技術含量的部落格文章來推廣的Nebula無論star數量還是fork數量都比CJsonObject少(可能跟受眾數量有關係)。Bwar始終認為絕大部分使用JSON的場景下,易用性與開發效率才是第一位的,而不是解析效能。在易用性上,說CJsonObject讓JSON如C++原生資料結構一般並不為過,所以不避黃婆賣瓜之嫌再極力推薦!CJsonObject有良好的更新和維護,對使用者提的issue響應非常及時,開源一年增加了不少原本不支援但使用者又需要的功能特性。

  CJsonObject在Bwar的重點開源專案Nebula中大量使用,無論對Bwar自己還是對外部開發者,都有持續更新維護的需要。順便為打個小廣告,Nebula是一個強大的IoC網路框架,用於以C++快速構建高併發、分散式和彈性的訊息驅動應用程式。適用於即時通訊、資料採集、實時計算、訊息推送、web後臺服務等應用場景,Nebula已有即時通訊、埋點資料採集及實時分析的生產應用案例。如果覺得CJsonObject不錯,給Nebula也點個star,謝謝。

  CJsonObject是基於cJSON全新開發一個C++版的JSON庫,CJsonObject的最大優勢是輕量,簡單好用,開發效率極高。CJsonObject只有4個檔案,拷貝到自己程式碼裡原始碼級整合即可,無須編譯成庫,且跨平臺和編譯器。與大部分json解析庫訪問多層巢狀json非常麻煩不同,CJsonObject對多層巢狀json的讀取和生成使用非常簡單。

  針對開發者在部落格和CJsonObject專案的issue提的問題整理了一個FAQ如下:

FAQ

  • 1. 如何遍歷json的key,並取其value?
std::string strTraversingKey;
std::string strTraversingValue;
while(oJson.GetKey(strTraversingKey))
{
    if (oJson.Get(strTraversingKey, strTraversingValue))
    {
        std::cout << strTraversing << "  :  " << strTraversingValue << std::endl;
    }
}

  GetKey()遍歷不適用於陣列,對json陣列呼叫GetKey()將直接返回false。呼叫GetKey()函式迴圈遍歷獲取當前所在層次的json key,GetKey()返回false表示已取完最後一個key,下次遍歷再呼叫GetKey()將重新從第一個key開始獲取。換一種說法,GetKey()遍歷json key的返回結果為:true,true,true ... true,false; true,true,true ... true,false; true,true,true ... true,false; 想要遍歷多少輪完全由使用者自己決定。

  如果需要中斷一次遍歷並重新開始,可以呼叫ResetTraversing()函式重置遍歷。

std::string strTraversingKey;
std::string strTraversingValue;
while(oJson.GetKey(strTraversingKey))
{
    if (strTraversingKey == "Auguest")
    {
        oJson.ResetTraversing();
        break;
    }
    if (oJson.Get(strTraversingKey, strTraversingValue))
    {
        std::cout << strTraversing << "  :  " << strTraversingValue << std::endl;
    }
}

// 因為上一個遍歷中斷時呼叫了ResetTraversing(),所以本次遍歷又是從第一個key開始。如果上一個遍歷中斷時未呼叫ResetTraversing(),那這次遍歷將是從上次終端的位置繼續,這通常不是遍歷的預期結果,因此,中斷遍歷時記得ResetTraversing()。
while(oJson.GetKey(strTraversingKey))
{
    if (oJson.Get(strTraversingKey, strTraversingValue))
    {
        std::cout << strTraversing << "  :  " << strTraversingValue << std::endl;
    }
}

  __注意:__對Json當前層次的key進行Add()或Delete()操作,將導致當前遍歷失效,下次呼叫GetKey()將獲取key從頭開始。

  • 2. Replace一個key時,是否需要原value型別與替換後value型別一致?

  Replace()函式對key進行替換,跟value型別無關。把一個value為int的替換為value為string,或將value替換為object或array都是可以的。但如非必要,建議替換後的value型別跟替換前的value型別相同。

  • 3. []和()的過載有什麼區別,為什麼要過載這兩個操作符?

  []的過載是操作JsonObject或JsonArray的,為了方便一層一層往下取巢狀的json,不適用於string、int等基本json型別;()的過載是Get()系列函式的更便捷的呼叫,如果十分肯定key是存在的不需要通過Get()的返回值判斷是否獲取成功,呼叫()比呼叫Get()編碼要快,不適用於操作JsonObject或JsonArray。

  []和()返回值是不一樣的,兩者不能混用。

  • 4. 如何用CJsonObject建立類似以下二維陣列?
{
    "test":[
        [{"test":1}],
        [{"test":2}]
    ]
}

  CJsonObject對多層巢狀json的操作非常靈活方便,對巢狀json的生成和讀取有許多種靈活用法。

neb::CJsonObject oTest;
oTest.AddEmptySubArray("test");
for (int i = 1; i < 3; ++i)
{
    neb::CJsonObject oDimension1;
    neb::CJsonObject oDimension2;
    oDimension2.Add("test", i);
    oDimension1.Add(oDimension2);
    oTest["test"].Add(oDimension1);
}
std::cout << oTest.ToString() << std::endl;

  這裡給出的只是其中一種寫法,其他幾種可以參考FAQ#5。

  • 5. 請問一下在使用CJsonObject如何建立如下形式的陣列?
{
    "employees": [
        { "firstName":"John" , "lastName":"Doe" },
        { "firstName":"Anna" , "lastName":"Smith" },
        { "firstName":"Peter" , "lastName":"Jones" }
    ]
}

  這裡給出三種生成上述json陣列的方式:

neb::CJsonObject oJson;
oJson.AddEmptySubArray("employees");
oJson["employees"].Add(neb::CJsonObject("{\"firstName\":\"John\" , \"lastName\":\"Doe\"}"));
oJson["employees"].Add(neb::CJsonObject("{\"firstName\":\"Anna\" , \"lastName\":\"Smith\"}"));
oJson["employees"].Add(neb::CJsonObject("{\"firstName\":\"Peter\" , \"lastName\":\"Jones\"}"));
neb::CJsonObject oJson;
oJson.AddEmptySubArray("employees");
oJson["employees"].Add(neb::CJsonObject("{}"));
oJson["employees"][0].Add("firstName", "John");
oJson["employees"][0].Add("lastName", "Doe");
oJson["employees"].Add(neb::CJsonObject("{}"));
oJson["employees"][1].Add("firstName", "Anna");
oJson["employees"][1].Add("lastName", "Smith");
oJson["employees"].Add(neb::CJsonObject("{}"));
oJson["employees"][2].Add("firstName", "Peter");
oJson["employees"][2].Add("lastName", "Jones");
neb::CJsonObject oJson;
neb::CJsonObject oJohn;
neb::CJsonObject oAnna;
neb::CJsonObject oPeter;
oJohn.Add("firstName", "John");
oJohn.Add("lastName", "Doe");
oAnna.Add("firstName", "Anna");
oAnna.Add("lastName", "Smith");
oPeter.Add("firstName", "Peter");
oPeter.Add("lastName", "Jones");
oJson.AddEmptySubArray("employees");
oJson["employees"].Add(oJohn);
oJson["employees"].Add(oAnna);
oJson["employees"].Add(oPeter);