2017-02-27 24 views
5

Zgodnie z Google JSON style guide zaleca się usunięcie pustych lub pustych wartości.Jak ignorować obiekty puste podczas pisania JSON z JsonCpp

Podczas korzystania z JsonCpp, w jaki sposób można usunąć wartości puste lub puste, zarówno ze struktury obiektu, jak i przy zapisie do strumienia?

Chcę następujący kod:

#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; 

do przedstawienia:

{ 
    "id": 4, 
} 
+0

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

Odpowiedz

4

Możesz dodać pre-proces, aby usunąć puste członków, coś jak:

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; 
     } 
    } 
} 

I więc w końcu:

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

Osobiście wolałbym opcję w programie piszącym, która pozwala odfiltrować puste/puste właściwości podczas pisania. W ten sposób można zdefiniować własną klasę, taką jak class MyFastWriter : public FastWriter, zastąpić printValue, aby odpowiednio obsłużyć typ objectValue i wywołać FastWriter::writeValue dla reszty. Niestety, JsonCpp API zdefiniował funkcję członka printValue jako prywatną, tak że nie można jej przesłonić (a nawet wywołać) z niestandardowej klasy pochodnej.

Dlatego widzę tylko trzy główne sposoby osiągnięcia tego, co chcesz: (1) Dostosowanie wartości json przed zapisem, (2) zdefiniowanie własnej klasy pisarzy i skopiowanie dużej ilości kodu z FastWriter lub (3) zmiana kod źródłowy: FastWriter.

Istnieje już odpowiednia odpowiedź dla opcji (1) dostarczonej przez Jarod42.

Opcja (2) i (3) mają główną wadę, którą można skopiować lub zmienić szczegóły implementacji, które mogą ulec zmianie w przyszłych wersjach JsonCpp; Ale nadal, jeśli zdajesz sobie sprawę z wad związanych z modyfikacją lub kopiowaniem kodu źródłowego biblioteki, może to być opcja. Może się zdarzyć, że podana wartość json będzie utrzymywać puste właściwości, jest bardzo duża i często musi być zapisywana; wtedy nie jest łatwo skopiować wartość, zmieniając ją tylko po to, by pisać, i następnie ją pisząc.

Jestem na pewno nie przyjacielem zmiany kodu źródłowego; Zresztą, zobacz przystosowany następującą wersję FastWriter::writeValue która osiąga wyjście chcesz:

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

Zauważ, że w zależności od pożądanej definicji * puste *, rekurencyjny przypadek byłby bardziej skomplikowany '{" a ":" a "," empty_rec ": {" empty ": null}}'. – Jarod42

0

jestem przy założeniu, że wartości ustawiasz wartości nie są stałe i jesteś zapisywania danych z klasy lub innego struktura danych. W takim przypadku możesz po prostu sprawdzić dane po stronie C++ i całkowicie pominąć część json["varName"].

Cokolwiek umieścisz w pliku JSON, będzie w ostatecznym JSON, ponieważ ustawiasz to pole w pliku JSON na coś. Jak już powiedziałeś, jest to wskazane, aby nie zawierało wartości NULL/pustych, ale nie jest koniecznością. Wartości NULL, puste lub wartości domyślne są nadal wartościami, które niektórzy mogą chcieć w swoim pliku JSON specjalnie, aby pokazać, że konkretna jednostka nie ma tego wpisu, ale wciąż jest polem w tych danych.

Użyłbym pustej tablicy, tak jak dla pola name w twoim pliku JSON, w ten sposób czytelnik może powiedzieć: "O ok, ten obiekt nie ma żadnych wartości nazwy" i jeśli to nie było " Powinno się to wydarzyć lub jeśli to dziwne, nawet klienci nietechniczni będą w stanie poprowadzić cię przez to i debugowanie będzie znacznie prostsze. Chyba że jest to część kodu sieciowego i potrzebujesz najszybszych czasów odpowiedzi. W przeciwnym razie po prostu dołącz to.

Złota zasada debugowania: pliki Thich ratują życie.