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

  • 2019 年 10 月 3 日
  • 筆記

  極力推薦一個簡單好用的C++JSON庫CJsonObject,讓使用json如使用C++原生的結構體那般方便,隨心所欲。CJsonObject是個優秀的C++JSON庫,也許會是你見過的最為簡單易用的C++json庫。CJsonObject的開源地址是https://github.com/Bwar/CJsonObjecthttps://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);