Developpez.com - Rubrique C++

Le Club des Développeurs et IT Pro

JsonCpp

Une nouvelle bibliothèque pour analyser le JSON en C++11

Le 2016-01-08 15:51:54, par LittleWhite, Responsable 2D/3D/Jeux
JsonCpp est une énième bibliothèque pour analyser le JSON en C++ sous licence MIT. Toutefois, malgré le côté déjà vu de celle-ci, vous pourriez être intéressé par JsonCpp pour :
  • son utilisation du C++11 ;
  • sa disponibilité en bibliothèque complètement implémentée dans les fichiers d'entêtes.


Autrement, celle-ci apporte les fonctionnalités habituelles permettant d'analyser les entrées au format JSON :
  • lire et écrire des données au format JSON ;
  • sérialisation/désérialisation ;
  • attacher des commentaires C++ aux éléments durant l'analyse ;
  • réécrire le document JSON en gardant les commentaires originaux.


Voici un exemple de code utilisant JsonCpp :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Json::Value root;   // 'root' will contain the root value after parsing. 
std::cin >> root; 
// You can also read into a particular sub-value. 
std::cin >> root["subtree"]; 
// Get the value of the member of root named 'encoding', 
// and return 'UTF-8' if there is no such member. 
std::string encoding = root.get("encoding", "UTF-8" ).asString(); 
// Get the value of the member of root named 'plug-ins'; return a 'null' value if 
// there is no such member. 
const Json::Value plugins = root["plug-ins"]; 
// Iterate over the sequence elements. 
for ( int index = 0; index < plugins.size(); ++index ) 
   loadPlugIn( plugins[index].asString() ); 
    
// Try other datatypes. Some are auto-convertible to others. 
foo::setIndentLength( root["indent"].get("length", 3).asInt() ); 
foo::setIndentUseSpace( root["indent"].get("use_space", true).asBool() ); 
// Since Json::Value has an implicit constructor for all value types, it is not 
// necessary to explicitly construct the Json::Value object. 
root["encoding"] = foo::getCurrentEncoding(); 
root["indent"]["length"] = foo::getCurrentIndentLength(); 
root["indent"]["use_space"] = foo::getCurrentIndentUseSpace(); 
// If you like the defaults, you can insert directly into a stream. 
std::cout << root; 
// Of course, you can write to `std::ostringstream` if you prefer. 
// If desired, remember to add a linefeed and flush. 
std::cout << std::endl;
Vous pouvez retrouver le projet sur GitHub.



Pour rappel, voici un exemple de données au format JSON :
Code JSON :
1
2
3
4
5
6
7
8
9
{ 
    "encoding" : "UTF-8", 
    "plug-ins" : [ 
        "python", 
        "c++", 
        "ruby" 
        ], 
    "indent" : { "length" : 3, "use_space": true } 
}



Votre opinion

Quelle bibliothèque utilisez-vous pour analyser les entrées au format JSON ?
De quelles fonctionnalités avez-vous absolument besoin dans ce type de bibliothèques ?

Source

GitHub
  Discussion forum
11 commentaires
  • jo_link_noir
    Membre expert
    Envoyé par Ehonn
    J'ai du mal à voir / comprendre le conflit
    Les boucle for-range ne fonctionnent pas alors que les fonctions d'itérateur existent. Mais sous un autre nom.

    Envoyé par Ehonn
    - les fonctions de la bibliothèque standard ne sont pas begin, end et flush mais std::begin, std::end et std::flush
    Pourtant, il ne faudrait pas précéder par std:: les fonctions utilitaires.

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    namespace kk {
      struct MonRange {
        struct iterator { /*...*/ };
        iterator Begin();
        iterator End();
      };
    
      MonRange::iterator begin(MonRange & r) { return r.Begin(); }
      MonRange::iterator end(MonRange & r) { return r.End(); }
    }
    //...
    
    std::vector<int> v;
    kk::MonRange r;
    int a[2];
    
    for (auto x : v) {} // ok
    for (auto x : r) {} // ok
    for (auto x : a) {} // ok
    
    // dépendant du namespace
    std::for_each(std::begin(v), std::end(v), blahblah); // ok
    std::for_each(kk::begin(r), kk::end(r), blahblah); // ok
    std::for_each(std::begin(a), std::end(a), blahblah); // ok
    
    // avec std::
    std::for_each(std::begin(v), std::end(v), blahblah); // ok
    std::for_each(std::begin(r), std::end(r), blahblah); // pas ok
    std::for_each(std::begin(a), std::end(a), blahblah); // ok
    
    // sans std::
    std::for_each(begin(v), end(v), blahblah); // ok
    std::for_each(begin(r), end(r), blahblah); // ok
    std::for_each(begin(a), end(a), blahblah); // pas ok
    
    // la bonne manière de faire
    
    using std::begin;
    using std::end;
    
    std::for_each(begin(v), end(v), blahblah); // ok
    std::for_each(begin(r), end(r), blahblah); // ok
    std::for_each(begin(a), end(a), blahblah); // ok
    Histoire que mes écris servent:
    Utilisation de swap et des fonctions utilitaires
    Délégation d'appel de fonctions utilitaires
  • grunk
    Modérateur
    La première release de jsoncpp datent de 2010, mais peut être vient elle effectivement de passer au c++11. Je lai utilisé il y'a quelques mois et l'ai finalement abandonné pour rapidjson (header only également) bien plus performante.
  • Vinorcola
    Membre régulier
    J'ai pas trouvé de doc en ligne... Y'a que la doc doxygen (mais pas envi de télécharger le projet juste pour voir la doc).

    J'ai utilisé RapidJson aussi, mais je trouve que cette bibliothèque a un très grand défaut : les fonctions commencent par des majuscule (WTF???). Du coup, impossible d'utiliser les boucles for each, impossible d'utiliser les std::stream. Bref, une incompatibilité complète avec le C++11 standard.

    Ensuite j'ai découvert celle-ci qui fonctionne plutôt bien : https://github.com/nlohmann/json
    Après niveau performance, j'ai pas fait de tests. Je m'en sers pour charger des confs au lancement des programmes. Donc la performance impacte peu.
  • Vinorcola
    Membre régulier
    Envoyé par Bousk
    Euh.. gni ??? Je vois pas le rapport.
    La boucle for each utilise les fonctions begin & end. RapidJson a eu la très bonne idée de les appeler Begin et End. Du coup, ça passe pas.
    L'écriture utilise la fonction Flush alors que les std::stream ont une fonction flush.
    J'imagine qu'il doit y avoir d'autres incompatibilités de la sorte, mais pour le moment, je n'ai trouver que ces 2 points là, qui étaient bloquants pour moi du coup

    Bref avant d'utiliser des conventions de nommage un peu farfelu, il faut penser à ce que ça implique derrière...
  • r0d
    Expert éminent
    Bonjour.

    Envoyé par LittleWhite
    Quelle bibliothèque utilisez-vous pour analyser les entrées au format JSON
    Perso j'utilise json_spirit.
    Ça fait le taf, c'est du c++11, c'est full template, mais je ne sais pas si c'est mieux que les autres car je n'ai jamais comparé.

    Envoyé par LittleWhite
    De quelles fonctionnalités avez-vous absolument besoin dans ce type de bibliothèques
    Moi ce que j'aimerais bien, ce serait de pouvoir tester la validité du json produit avant l'exportation (écriture sur disque ou en DB). Peut-être que c'est parce que je m'y prends mal, mais étant donné que je manipule des données pleines de garbage, mes json générés sont parfois invalides.
  • akrogames
    Membre actif
    Super ! C'est une bonne nouvelle un peu de renouveau en C++ 11 pour lire/écrire du JSON car c'est pas forcément user friendly.

    Je valide cette news et je m'en vais tester.
  • Bousk
    Rédacteur/Modérateur
    Envoyé par Vinorcola
    un très grand défaut : les fonctions commencent par des majuscule (WTF???). Du coup, impossible d'utiliser les boucles for each, impossible d'utiliser les std::stream. Bref, une incompatibilité complète avec le C++11 standard.
    Euh.. gni ??? Je vois pas le rapport.

    @grunk : donc rapidjson porte encore bien son nom ? bon à savoir
  • dragonjoker59
    Expert éminent sénior
    Envoyé par Vinorcola
    La boucle for each
    Tu parles probablement de range-based for loops?
  • Vinorcola
    Membre régulier
    Je parles de la boucle :

    Code :
    1
    2
    3
    4
    for (const auto& child : collection)
    {
        ...
    }
    Après, je ne connais pas forcément le nom officiel ^^
  • AoCannaille
    Expert confirmé
    Envoyé par Vinorcola
    La boucle for each utilise les fonctions begin & end. RapidJson a eu la très bonne idée de les appeler Begin et End. Du coup, ça passe pas.
    L'écriture utilise la fonction Flush alors que les std::stream ont une fonction flush.
    J'imagine qu'il doit y avoir d'autres incompatibilités de la sorte, mais pour le moment, je n'ai trouver que ces 2 points là, qui étaient bloquants pour moi du coup

    Bref avant d'utiliser des conventions de nommage un peu farfelu, il faut penser à ce que ça implique derrière...
    Tes préoccupations paraissent légitimes, hésite pas à en parler sur le github, voire même d'ajouter tes fonctions avec la bonne casse et de le reproposer au créateur.