2017-02-27 121 views
5

根據Google JSON style guide,建議刪除空值或空值。如何在使用JsonCpp編寫JSON時忽略空對象

使用JsonCpp時,如何從對象結構中刪除空值或空值,或者寫入流時?

我想下面的代碼:

#include <json/json.h> 
#include <json/writer.h> 

Json::Value json; 
json["id"] = 4; 
// The "name" property is an empty array. 
json["name"] = Json::Value(Json::arrayValue); 
Json::FastWriter fw; 
std::cout << fw.write(json) << std::endl; 

產生:

{ 
    "id": 4, 
} 
+0

'sed'/:\ W * null \ W *,/ d''? – YSC

回答

4

您可以添加預處理去除空成員,是這樣的:

void RemoveNullMember(Json::Value& node) 
{ 
    switch (node.type()) 
    { 
     case Json::ValueType::nullValue: return; 
     case Json::ValueType::intValue: return; 
     case Json::ValueType::uintValue: return; 
     case Json::ValueType::realValue: return; 
     case Json::ValueType::stringValue: return; 
     case Json::ValueType::booleanValue: return; 
     case Json::ValueType::arrayValue: 
     { 
      for (auto &child : node) 
      { 
       RemoveNullMember(child); 
      } 
      return; 
     } 
     case Json::ValueType::objectValue: 
     { 
      for (const auto& key : node.getMemberNames()) 
      { 
       auto& child = node[key] 
       if (child.empty()) // Possibly restrict to any of 
            // nullValue, arrayValue, objectValue 
       { 
        node.removeMember(key); 
       } 
       else 
       { 
        RemoveNullMember(node[key]); 
       } 
      } 
      return; 
     } 
    } 
} 

而且所以最後:

Json::Value json; 
json["id"] = 4; 
json["name"] = Json::Value(Json::arrayValue); // The "name" property is an empty array. 
RemoveNullMember(json); // Or make a copy before. 
Json::FastWriter fw; 
std::cout << fw.write(json) << std::endl; 
1

就我個人而言,我更喜歡在編寫器中允許在寫入時過濾掉空/空屬性的選項。因此,可以定義像class MyFastWriter : public FastWriter這樣的自己的類,相應地替代printValue來處理類型objectValue,並且其餘的請求FastWriter::writeValue。不幸的是,JsonCpp API已經將成員函數printValue定義爲私有的,因此您無法從自定義派生類中覆蓋它(甚至不會調用它)。 (1)在寫入之前調整json值,(2)定義一個自己的作家類並從FastWriter複製很多代碼,或者(3)更改源代碼爲FastWriter

Jarod提供的選項(1)已經有了正確的答案。選項(2)和(3)共享主要缺點,即您複製或更改可能在JsonCpp未來版本中更改的實現細節;但是,如果人們非常清楚改變或複製圖書館的源代碼所帶來的弊端,它可能是一種選擇。一種情況可能是,手頭的json值應該保持空的屬性,非常大,必須經常寫;那麼複製這個值就變得很不方便,改變它只是爲了寫,然後一次又一次地寫。

我當然不是改變源代碼的朋友;無論如何,看到FastWriter::writeValue以下改編版本,實現了輸出你想要的:

void FastWriter::writeValue(const Value& value) { 
    switch (value.type()) { 

    // cases handling the other value.types remain as is... 
    ... 

    // case handling objectValue is adapted: 
    case objectValue: { 
    Value::Members members(value.getMemberNames()); 
    document_ += '{'; 

    // inserted flag indicating that the first element is to be written: 
    bool isFirst = true; 

    for (Value::Members::iterator it = members.begin(); it != members.end(); 
     ++it) { 

     const std::string& name = *it; 

     // inserted to skip empty/null property values 
     if(value[name].empty() || value[name].isNull()) 
      continue; 

// Replaced: necessary because the first written entry is not necessarily members.begin: 
//  if (it != members.begin()) 
//  document_ += ','; 
     if (!isFirst) 
      document_ += ','; 
     else 
      isFirst = false; 

     // Kept as is...    
     document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())); 
     document_ += yamlCompatiblityEnabled_ ? ": " : ":"; 
     writeValue(value[name]); 
    } 
    document_ += '}'; 
    } break; 
    } 
} 
+1

請注意,根據所需的* empty *定義,遞歸的情況會更復雜。{「a」:「a」,「empty_rec」:{「empty」:null}}'。 – Jarod42

0

我假設你設置的值不是恆定值,你就從一個類或其他一些保存數據數據結構。在這種情況下,您可以簡單地檢查C++端的數據並完全跳過json["varName"]部分。

無論你放在JSON文件中的是什麼,都會在最後的JSON中,因爲你將該字段設置爲JSON文件。正如你所說,這是建議不包括NULL /空值,但它不是必須的。 NULL,空值或默認值仍然是一些人可能希望在他們的JSON文件中專門顯示特定實體沒有該條目但它仍然是該數據中的字段的值。

我會在你的JSON文件中使用name字段的空數組,這樣讀者可以說「哦好吧,這個對象沒有任何名稱值」,如果這不是'假設要發生,或者如果感覺有點奇怪,即使非技術型客戶也能夠引導你完成並且調試會更簡單。除非這是網絡代碼的一部分,並且您需要有最快的響應時間。否則,只需包含它。

調試的黃金法則:Thich文件拯救生命。

相關問題