I am using Jsoncpp to parse json-formats for c++.
I do not understand how it works though; there is a lack of documentation and examples to get me started, and I was wondering if anyone could give me some quick pointers. The only examples I've found deals with files...
I'm using a HTTP stack to get a json-message in a buffer. For example, a buffer contains the message {"state":"Running"}. How do I use the Json::reader to parse this? Again the only example I've found deals with reading from files
How do you write values to a Json-message? For example I want to write "monkey : no" and "running : yes" to a Json-message which I can then use in my GET request.
Thanks
UPDATE:
on 1), for example, how to parse a buffer containing a json-message like this:
char* buff;
uint32_t buff_size;
Maybe this is good sample for first part of your question:
Json::Value values;
Json::Reader reader;
reader.parse(input, values);
Json::Value s = values.get("state","default value");
There is anything but lack of documentation. Yes, it's mainly reference documentation, but it's quite good and well cross-linked.
Just read the documentation
Just use this class or possibly use the other class
Sample code for your reference, below:
file.json
{
"B":"b_val2",
"A":{
"AA":"aa_val1",
"AAA" : "aaa_val2",
"AAAA" : "aaaa_val3"
},
"C":"c_val3",
"D":"d_val4"
}
jsoncpp usage scenario as below, for above sample json file.
#include <iostream>
#include "json/json.h"
#include <fstream>
using namespace std;
int main(){
Json::Value root;
Json::Reader reader;
const Json::Value defValue; //used for default reference
std::ifstream ifile("file.json");
bool isJsonOK = ( ifile != NULL && reader.parse(ifile, root) );
if(isJsonOK){
const Json::Value s = root.get("A",defValue);
if(s.isObject()){
Json::Value s2 = s.get("AAA","");
cout << "s2 : " << s2.asString() << endl;
}else{
cout << "value for key \"A\" is not object type !" << endl;
}
}
else
cout << "json not OK !!" << endl;
return 1;
}
Output::
s2 : aaa_val2
Additionally, I have used the "amalgamate.py" for generating and using the jsoncpp for the sample source above.
Related
I currently have a *.cpp file where I import the needed *.proto.h file and instantiate an object based on one of the messages(Heartbeat) from my *.proto file. My goal is to use the set_value(), SerializeToString(), and ParseFromString().I've had success accomplishing the first two tasks. When using ParseFromString() not output is produced to the screen. I'm pretty new to protobufs so there may be something I'm overlooking. This is my code.
#include <iostream>
#include <fstream>
#include <string>
#include "cpnt.pb.h"
using namespace std;
int main()
{
wombat::HeartBeat h;
string m;
string t;
string v;
h.set_value(1);
v = h.SerializeToString(&m);
t = h.ParseFromString(v);
cout << "\n The message received is:" << h.value();
cout << "\n The binary data stored in v is:" << v;
cout << "\n The parsed data stored in t is:" << t <<::endl;
return 0;
}
And this is a printout of the output:
You misunderstood how SerializeToString works. h.SerializeToString(&m); serializes h and stores the result in m. h.ParseFromString(v); parsed from the string v to set members of h. Hence it should be
h.set_value(1);
h.SerializeToString(&m);
h.ParseFromString(m);
Both functions retun a bool, but I admit that I didn't find what it is good for in the documentation. Probably to signal an error.
Today I did a lot of research online about how to create a directory on C++
and found a lot of way to do that, some easier than others.
I tried the _mkdir function using _mkdir("C:/Users/..."); to create a folder. Note that the argument of function will be converted into a const char*.
So far, so good, but when I want to change the path, it does not work (see the code below). I have a default string path "E:/test/new", and I want to create 10 sub-folders: new1, new2, newN, ..., new10.
To do that, I concatenate the string with a number (the counter of the for-loop), converted into char using static_cast, then I transform the string using c_str(), and assign it to a const char* variable.
The compiler has no problem compiling it, but it doesn't work. It prints 10 times "Impossible create folder n". What's wrong?
I probably made a mistake when transforming the string using c_str() to a get a const char*?.
Also, is there a way to create a folder using something else? I looked at CreateDirectory(); (API) but it uses keyword like DWORD HANDLE, etc., that are a little bit difficult to understand for a no-advanced level (I don't know what these mean).
#include <iostream>
#include <Windows.h>
#include<direct.h>
using namespace std;
int main()
{
int stat;
string path_s = "E:/test/new";
for (int i = 1; i <= 10; i++)
{
const char* path_c = (path_s + static_cast<char>(i + '0')).c_str();
stat = _mkdir(path_c);
if (!stat)
cout << "Folder created " << i << endl;
else
cout << "Impossible create folder " << i << endl;
Sleep(10);
}
return 0;
}
If your compiler supports c++17, you can use filesystem library to do what you want.
#include <filesystem>
#include <string>
#include <iostream>
namespace fs = std::filesystem;
int main(){
const std::string path = "E:/test/new";
for(int i = 1; i <= 10; ++i){
try{
if(fs::create_directory(path + std::to_string(i)))
std::cout << "Created a directory\n";
else
std::cerr << "Failed to create a directory\n";\
}catch(const std::exception& e){
std::cerr << e.what() << '\n';
}
}
return 0;
}
The problem is that (path_s + static_cast<char>(i + '0')) creates a temporary object. One whose life-time ends (and is destructed) just after c_str() has been called.
That leaves you with a pointer to a string that no longer exist, and using it in almost any way will lead to undefined behavior.
Instead save the std::string object, and call c_str() just when needed:
std::string path = path_s + std::to_string(i);
_mkdir(path.c_str());
Note that under Linux, you can use the mkdir command as follows:
#include <sys/stat.h>
...
const int dir_err = mkdir("foo", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (-1 == dir_err){
printf("Error creating directory!n");
exit(1);
}
More information on it can be gleaned from reading man 2 mkdir.
I'm still fairly new to C++ and programming so I might just be missing something big here.
I'm trying to create a chatbot for a library, deals with opening times ect and other things. I want the chatbot to be able to pickup key words in a input and then be able to call the right function that will be able to give some text back to them.
For example:
user: what time is the library open till?
//chatbot picks up the key word 'open' and returns the right function
chatbot: the libraries open between 6 and 5
It shouldn't be as hard as I am finding it to be able to get the chatbot to do this.
The function I'm having trouble with:
std::string GetKeywords(){
std::string KQuery = GetQuery();
std::vector<std::string> keywords{"open", "opening", "times", "close", "closing", "shut"};
if(std::find(keywords.begin(), keywords.end(), KQuery) != keywords.end()){
std::cout << "Library is open when I say it is" << std::endl;
}
return 0;
};
This is returning a memory error and is the only place in my code which throws an issue.
All my code:
#include <iostream>
#include <string>
#include <vector>
#include "FinalProject.hpp"
//introducing funtions
void PrintIntro();
std::string GetQuery();
std::string RunScripts();
std::string GetKeywords();;
// introducing chatbot
RunScript ChatBot;
int main(){
PrintIntro();
GetQuery();
GetKeywords();
};
void PrintIntro(){
//printing introductory text to ask the user for input
std::cout << "Hi, I'm Librarius, I'm here to help you with University library queries" << std::endl;
std::cout << "I can help you with the following: \n Spaces to study \n Opening times \n Taking out books \n Returning books\n" << std:: endl;
std::cout << "Ask away!" << std::endl;
return;
};
std::string GetQuery(){
//getting input from the user
std::string Query = "";
std::getline(std::cin, Query);
if(Query.empty()){
//checking to see if the user hasnt entered anything
std::cout << "Hey! Why didnt you enter anything?! I don't want to waste my time!" << std::endl;
};
return Query;
};
std::string GetKeywords(){
std::string KQuery = GetQuery();
std::vector<std::string> keywords{"open", "opening", "times", "close", "closing", "shut"};
if(std::find(keywords.begin(), keywords.end(), KQuery) != keywords.end()){
std::cout << "Library is open when I say it is" << std::endl;
}
return 0;
};
//using the input got from the user to decide which script to run
//TODO analyse the users keywords and decide on a script to run
//TODO return an appropriate script
Thanks for your help!
The problem with
std::find(keywords.begin(), keywords.end(), KQuery)
is it is going to see if the entire string in KQuery matches one of your keywords. Since KQuery has a sentence in it, it isn't going to find a match. What you need to do is loop through all the keywords and see if KQuery.find(keyword) returns a valid result.
You can do that using std::find_if and a lambda like
std::find_if(keywords.begin(), keywords.end(),
[&](auto const& keyword){ return KQuery.find(keyword) != std::string::npos; });
This will return an iterator to the first keyword it finds in KQuery or keywords.end() if none of the keywords are found.
I'm using jsoncpp on ubuntu 14.04. Installed with apt-get libjsoncpp-dev libjsoncpp0. I'm not sure what version of jsoncpp it is.
I had a typo in a key name (in C++) and it was really tricky to track down. Consider this example:
#include <iostream>
#include <jsoncpp/json/json.h>
int main(int argc, char** argv) {
Json::Reader reader(Json::Features::strictMode());
Json::Value obj;
std::string json = "{\"mykey\" : 42}";
if (!reader.parse(json.c_str(), obj)) {
std::cout << "JSON parse error" << std::endl;
}
const Json::Value& mykey1 = obj["mykey"];
std::cout << "mykey1:" << mykey1.asInt() << std::endl;
const Json::Value& mykey2 = obj["mykey_typo"];
std::cout << "mykey2:" << mykey2.asInt() << std::endl;
return 0;
}
I'm getting this output:
mykey1:42
mykey2:0
The fact that an access to a non-existent key produces a value of 0 is scary to me. It means if there is a typo the program will just use zero instead of the correct value. I'd rather know there was a typo. Is there a way to make jsoncpp throw or what is the recommended approach here?
I can write a helper that calls isMember and then does the lookup, but was wondering if the library itself has a solution.
It looks like by design the behavior of jsoncpp asInt returns 0 when the value is null. Perhaps do a null check before using the value?
Take a look at line 721 in the source.
I have started implementing Microsoft Cognitive Services using C++. I have a C++ String array(faceIds array)
string faceIds[] ={
"29e874a8-a08f-491f-84e8-eac263d51fe1",
"6f89f38a-2411-4f6c-91b5-15eb72c17c22",
"7284b730-6dd7-47a3-aed3-5dadaef75d76",
"1fc794fa-3fd4-4a78-af11-8f36c4cbf14c",
"3e57afca-bd1d-402e-9f96-2cae8dbdfbfa",
"c2a4e0f5-4277-4f5a-ae28-501085b05209",
"23b5910e-9c32-46dd-95f3-bc0434dff641"
};
Then, I try to convert string array(C++) to json string.
JSONObject jsnobject = new JSONObject(10);
JSONArray jsonArray = jsnobject.getJSONArray(faceIds);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject explrObject = jsonArray.getJSONObject(i);
}
But, I got problem. So, My question is, How to convert C++ string array to json?
Thank in Advance.
Your question doesn't precisely identify your input and expected output. Are you parsing the C++ from a file? I can't tell.
If the first code block is an autogenerated input file and will always have that whitespace pattern and the JSON equivalent is your desired output, replace the first line with "[\n" and the last line with "]/n" and you're done.
If you can't guarantee the white space pattern of the input file, then you will need a C++ parser to generate an AST (abstract symbol tree) that you can traverse to find the faceIds array RHS (right hand side) and then do the same thing as shown below from that AST collection.
If you simply want to iterate in C++ through faceIds, then the following code should produce the desired JSON string:
#include <iostream>
#include <sstream>
std::string faceIds[] = {
"29e874a8-a08f-491f-84e8-eac263d51fe1",
"6f89f38a-2411-4f6c-91b5-15eb72c17c22",
"7284b730-6dd7-47a3-aed3-5dadaef75d76",
"1fc794fa-3fd4-4a78-af11-8f36c4cbf14c",
"3e57afca-bd1d-402e-9f96-2cae8dbdfbfa",
"c2a4e0f5-4277-4f5a-ae28-501085b05209",
"23b5910e-9c32-46dd-95f3-bc0434dff641"
};
int main() {
std::ostringstream ostr;
ostr << '[' << std::endl;
int last = std::extent<decltype(faceIds)>::value - 1;
int i = 0;
while (i < last)
ostr << " \"" << faceIds[i ++] << "\"," << std::endl;
ostr << " \"" << faceIds[i] << "\"" << std::endl;
ostr << ']' << std::endl;
std::cout << ostr.str();
return 0;
}
If you want some library's object representation, then you'll have to identify what library you are using so we can review its API. Whatever library you use, you could always just run whatever parse method it has on ostr.str() above, but we could find a more efficient method to build the equivalent JSON tree if you identified the JSON library. One can't uniquely identify the library from an object name like JSONObject, which is a class name used in dozens of libraries.
This is a robust cross platform solution to working with JSON in C++ https://github.com/nlohmann/json. I'm sure Microsoft has some library locked to their own OS too. The examples are clear.
I think the nlohmann c++ library is useful in your case.