J'essaie de lire dans un fichier JSON. Jusqu'à présent, je me suis concentré sur l'utilisation de la bibliothèque jsoncpp
. Cependant, la documentation est assez difficile à comprendre pour moi. Quelqu'un pourrait-il expliquer en termes simples ce qu'il fait?
Dites que j'ai un people.json
qui ressemble à ceci:
{"Anna" : {
"age": 18,
"profession": "student"},
"Ben" : {
"age" : "nineteen",
"profession": "mechanic"}
}
Qu'est-ce qui se passe quand je lis ceci dans? Puis-je créer une sorte de structure de données people
que je peux indexer par Anna
et Ben
ainsi que age
et profession
? Quel serait le type de données de people
? J'ai pensé que cela ressemblerait à une carte (imbriquée), mais les valeurs de carte doivent toujours avoir le même type, n'est-ce pas?
J'ai déjà travaillé avec python auparavant et mon objectif (qui peut être mal défini pour C++) est d'obtenir l'équivalent d'un dictionnaire python imbriqué.
Oui, vous pouvez créer une structure de données imbriquée people
qui peut être indexée par Anna
et Ben
. Cependant, vous ne pouvez pas l'indexer directement par age
et profession
(j'aborderai cette partie dans le code).
Le type de données de people
est de type Json::Value
(défini dans jsoncpp). Vous avez raison, cela ressemble à la carte imbriquée, mais Value
est une structure de données définie de manière à ce que plusieurs types puissent être stockés et accessibles. Cela ressemble à une carte avec string
comme clé et Json::Value
comme valeur. Il peut également s'agir d'un mappage entre unsigned int
en tant que clé et Json::Value
en tant que valeur (dans le cas de tableaux JSON).
Voici le code:
#include <json/value.h>
#include <fstream>
std::ifstream people_file("people.json", std::ifstream::binary);
people_file >> people;
cout<<people; //This will print the entire json object.
//The following lines will let you access the indexed objects.
cout<<people["Anna"]; //Prints the value for "Anna"
cout<<people["ben"]; //Prints the value for "Ben"
cout<<people["Anna"]["profession"]; //Prints the value corresponding to "profession" in the json for "Anna"
cout<<people["profession"]; //NULL! There is no element with key "profession". Hence a new empty element will be created.
Comme vous pouvez le constater, vous ne pouvez indexer l'objet json qu'en fonction de la hiérarchie des données d'entrée.
Consultez le référentiel JSON de nlohmann sur GitHub . J'ai trouvé que c'était le moyen le plus pratique de travailler avec JSON.
Il est conçu pour se comporter comme un conteneur STL, ce qui rend son utilisation très intuitive.
Exemple (avec le code source complet) pour lire un fichier de configuration json:
https://github.com/sksodhi/CodeNuggets/tree/master/json/config_read
> pwd
/root/CodeNuggets/json/config_read
> ls
Makefile README.md ReadJsonCfg.cpp cfg.json
> cat cfg.json
{
"Note" : "This is a cofiguration file",
"Config" : {
"server-ip" : "10.10.10.20",
"server-port" : "5555",
"buffer-length" : 5000
}
}
> cat ReadJsonCfg.cpp
#include <iostream>
#include <json/value.h>
#include <jsoncpp/json/json.h>
#include <fstream>
void
displayCfg(const Json::Value &cfg_root);
int
main()
{
Json::Reader reader;
Json::Value cfg_root;
std::ifstream cfgfile("cfg.json");
cfgfile >> cfg_root;
std::cout << "______ cfg_root : start ______" << std::endl;
std::cout << cfg_root << std::endl;
std::cout << "______ cfg_root : end ________" << std::endl;
displayCfg(cfg_root);
}
void
displayCfg(const Json::Value &cfg_root)
{
std::string serverIP = cfg_root["Config"]["server-ip"].asString();
std::string serverPort = cfg_root["Config"]["server-port"].asString();
unsigned int bufferLen = cfg_root["Config"]["buffer-length"].asUInt();
std::cout << "______ Configuration ______" << std::endl;
std::cout << "server-ip :" << serverIP << std::endl;
std::cout << "server-port :" << serverPort << std::endl;
std::cout << "buffer-length :" << bufferLen<< std::endl;
}
> cat Makefile
CXX = g++
PROG = readjsoncfg
CXXFLAGS += -g -O0 -std=c++11
CPPFLAGS += \
-I. \
-I/usr/include/jsoncpp
LDLIBS = \
-ljsoncpp
LDFLAGS += -L/usr/local/lib $(LDLIBS)
all: $(PROG)
@echo $(PROG) compilation success!
SRCS = \
ReadJsonCfg.cpp
OBJS=$(subst .cc,.o, $(subst .cpp,.o, $(SRCS)))
$(PROG): $(OBJS)
$(CXX) $^ $(LDFLAGS) -o $@
clean:
rm -f $(OBJS) $(PROG) ./.depend
depend: .depend
.depend: $(SRCS)
rm -f ./.depend
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -MM $^ > ./.depend;
include .depend
> make
Makefile:43: .depend: No such file or directory
rm -f ./.depend
g++ -g -O0 -std=c++11 -I. -I/usr/include/jsoncpp -MM ReadJsonCfg.cpp > ./.depend;
g++ -g -O0 -std=c++11 -I. -I/usr/include/jsoncpp -c -o ReadJsonCfg.o ReadJsonCfg.cpp
g++ ReadJsonCfg.o -L/usr/local/lib -ljsoncpp -o readjsoncfg
readjsoncfg compilation success!
> ./readjsoncfg
______ cfg_root : start ______
{
"Config" :
{
"buffer-length" : 5000,
"server-ip" : "10.10.10.20",
"server-port" : "5555"
},
"Note" : "This is a cofiguration file"
}
______ cfg_root : end ________
______ Configuration ______
server-ip :10.10.10.20
server-port :5555
buffer-length :5000
>
Essentiellement, javascript et C++ fonctionnent sur deux principes différents. Javascript crée un "tableau associatif" ou une table de hachage, qui correspond à une clé de chaîne, qui est le nom du champ, à une valeur. C++ dispose des structures en mémoire, donc les 4 premiers octets sont un entier, qui est un âge, alors peut-être avons-nous une chaîne fixe de 32 octets qui représente le "métier".
Donc, javascript gérera des choses comme "l'âge" étant 18 ans sur un disque et "19 ans" sur un autre. C++ ne peut pas. (Cependant, C++ est beaucoup plus rapide).
Donc, si nous voulons gérer JSON en C++, nous devons construire le tableau associatif à partir de la base. Ensuite, nous devons étiqueter les valeurs avec leurs types. S'agit-il d'un entier, d'une valeur réelle (probablement renvoyée sous la forme "double"), d'une valeur booléenne? Il s'ensuit qu'une classe JSON C++ est un assez gros morceau de code. En pratique, nous implémentons un peu du moteur javascript en C++. Nous transmettons ensuite à notre analyseur JSON le JSON sous forme de chaîne, qui le marque et nous donne des fonctions pour interroger le JSON à partir de C++.
stocker des peuples comme ça
{"Anna" : {
"age": 18,
"profession": "student"},
"Ben" : {
"age" : "nineteen",
"profession": "mechanic"}
}
causera des problèmes, en particulier si différents peuples ont le même nom ..
plutôt utiliser un tableau stockant des objets comme celui-ci
{
"peoples":[
{
"name":"Anna",
"age": 18,
"profession": "student"
},
{
"name":"Ben",
"age" : "nineteen",
"profession": "mechanic"
}
]
}
comme ceci, vous pouvez énumérer des objets, ou accéder à des objets par index numérique . rappelez-vous que json est une structure de stockage, et non pas un trieur ou un indexeur dynamique .