2017-02-27 2 views
5

Selon le Google JSON style guide, il est conseillé de supprimer les valeurs vides ou nulles.Comment ignorer les objets NULL lors de l'écriture de JSON avec JsonCpp

Lors de l'utilisation de JsonCpp, comment les valeurs vides ou nulles peuvent-elles être supprimées, soit à partir de la structure de l'objet, soit lors de l'écriture dans un flux?

Je veux le code suivant:

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

pour produire:

{ 
    "id": 4, 
} 
+0

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

Répondre

4

Vous pouvez ajouter un pré-traitement pour éliminer les membres vides, quelque chose comme:

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

Et donc finalement:

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

Personnellement, je préférerais une option dans l'éditeur qui permet de filtrer les propriétés vides/nulles lors de l'écriture. De ce fait, on pourrait définir une propre classe comme class MyFastWriter : public FastWriter, remplacer printValue pour gérer le type objectValue en conséquence et appeler le FastWriter::writeValue pour le reste. Malheureusement, l'API JsonCpp a défini la fonction membre printValue comme privée, de sorte que vous ne pouvez pas la remplacer (et même ne pas l'appeler) à partir d'une classe dérivée personnalisée.

Par conséquent, je ne vois que trois façons principales de réaliser ce que vous voulez: (1) Adaptation de la valeur json avant écriture, (2) définition d'une propre classe d'écriture et copie de beaucoup de code de FastWriter, ou (3) changement le code source de FastWriter.

Il existe déjà une réponse correcte pour l'option (1) fournie par Jarod42. L'option (2) et (3) partagent l'inconvénient majeur que vous copiez ou modifiez les détails d'implémentation qui pourraient changer dans les futures versions de JsonCpp; Mais encore, si l'on est très conscient des inconvénients liés à la modification ou à la copie du code source d'une bibliothèque, cela peut être une option. Une situation pourrait être que la valeur json en main doit garder des propriétés vides, est très grande et doit être écrite assez souvent; il devient alors difficile de copier la valeur, de la modifier juste pour l'écrire et de l'écrire encore et encore. Je suis à coup sûr pas un ami de la modification du code source; Quoi qu'il en soit, voir la version suivante adaptée de FastWriter::writeValue qui réalise la sortie que vous voulez:

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

Notez qu'en fonction de la définition voulue de * empty *, le cas récursif serait plus compliqué '{" a ":" a "," empty_rec ": {" empty ": null}}'. – Jarod42

0

Je suppose que les valeurs de réglage sont des valeurs es pas constantes et vous enregistrez les données d'une classe ou d'une autre Structure de données. Dans ce cas, vous pouvez simplement vérifier les données côté C++ et ignorer complètement la partie json["varName"]. Quoi que vous mettiez dans un fichier JSON, ce sera dans le JSON final, car vous définissez ce champ dans le fichier JSON à quelque chose.

Comme vous l'avez dit, il est conseillé pour ne pas inclure des valeurs NULL/vides, mais ce n'est pas un must. Les valeurs NULL, vides ou par défaut sont des valeurs que certaines personnes pourraient vouloir dans leur fichier JSON pour montrer spécifiquement que cette entité particulière n'a pas cette entrée mais c'est toujours un champ dans ces données.

J'utiliserais le tableau vide tel quel pour le champ name dans votre fichier JSON, de cette façon le lecteur pourra dire "Oh ok, cet objet n'a aucune valeur de nom" et si ça ne l'était pas Je suppose que cela se produirait ou, si cela vous semblait bizarre, même des clients non techniques pourraient vous guider et le débogage serait beaucoup plus simple. À moins que cela ne fasse partie d'un code réseau et que vous ayez besoin des temps de réponse les plus rapides. Sinon, il suffit de l'inclure.

Règle d'or du débogage: les fichiers Thich sauvent des vies.