I'm connecting to a WebSocket whom always replies in JSON.
I see there is an extract_string method for websocket_incoming_message however after trying numerous things with json:value it seems as though you can only construct JSON arrays on-the-fly by inserting key-value pairs one-by-one.
Am I missing something here or is there a way to take the output from websocket_incoming_message and directly convert it into a json:value array?
wsClient.set_message_handler([=](websocket_incoming_message msg)
{
// handle message from server...
printf("[WebSocket INBOUND]: %s", msg.extract_string().get().c_str());
printJSON(json::value::parse(conversions::to_string_t(msg.extract_string().get())));
});
printJSON runs through the json::value and prints each key-value-pair.
Unhandled exception at 0x00007FF866923FB8 in RestAPI.exe: Microsoft
C++ exception: web::json::json_exception at memory location
0x0000003E553FDDC0. occurred
Console Output:
[WebSocket INBOUND]:
{"t":null,"s":null,"op":10,"d":{"heartbeat_interval":41250,"_trace":["gateway-prd-main-cr3x"]}}
Even though we can compile and run the application, I figure the exception is being caused due to the fact that were passing a string containing a JSON Table and not a single element? Does this mean I need to manually parse the string and pull out each key-value-pair while simultaneously building the json array?
There must be a way to do this, it seems like basic needed functionality..
A similar unresolved question
Any help here would be greatly appreciated!
Thank you for your time.
Try catching web::json::json_exception and print the message, it may give you a hint about what's wrong
I got the complete solution .please try to use boost pacakges from nuget. The documentation will help you to parse the json data from string. I think jsoncpp is not an updated packages available in the nuget.so please try boost packages available in the nuget.
MYJSON STRING
{"action":"refresh_dashboard","data":{"users_list":[{"user_id":"901e6076ff351cfc2195fb86f8438a26","extensions":["1002"],"name":"Karthik M"},{"user_id":"7d617ef5b2390d081d901b0d5cd108eb","extensions":["1015"],"name":"Synway User2"},{"user_id":"c8f667f7d663e81f6e7fa34b9296f067","extensions":["1012"],"name":"Rahib Video"},{"user_id":"cc3f94ecc14ee9c55670dcde9adc1887","extensions":["1006"],"name":"Rounak S Kiran"},{"user_id":"6c29ebdb34e1761fdf9423c573087979","extensions":["1003"],"name":"Amar Nath"},{"user_id":"8e15c2d95d4325cb07f0750846966be8","extensions":["1011"],"name":"TLS User"},{"user_id":"2fc4142bdacf83c1957bda0ad9d50e3d","extensions":["1014"],"name":"Synway User1"},{"user_id":"74d5b5a9aca1faa4c2f217ce87b621d8","extensions":["1008"],"name":"Robin Raju"},{"user_id":"a7ad7e73bf93ea83c8efdc1723cba198","extensions":["1007"],"name":"Arshad Arif"},{"user_id":"b55146df593ec8d09e5fe12a8a4c1108","extensions":["1001"],"name":"Rahib Rasheed"},{"user_id":"391391de005a8f5403c7b5591f462ea1","extensions":["1013"],"name":"Sangeeth J"},{"user_id":"3258f7ae4ae1db60435cbcf583f64a89","extensions":["1009"],"name":"Aby TL"},{"user_id":"90bc84e5e8a3427fe35e99bd4386de95","extensions":["1010"],"name":"Prince T"},{"user_id":"b501ef5b270a196afc0eed557ca74237","extensions":["1005"],"name":"Jineed AJ"},{"user_id":"1422af351e06adeab2de92f5a633a444","extensions":["1004"],"name":"Ashok PA"}],"busy_users":[],"reg_users":[{"user_id":"901e6076ff351cfc2195fb86f8438a26","status":"registered"},{"user_id":"6c29ebdb34e1761fdf9423c573087979","status":"registered"}],"contacts":[{"owner_id":"901e6076ff351cfc2195fb86f8438a26","status":"ready"},{"owner_id":"6c29ebdb34e1761fdf9423c573087979","status":"ready"}]}}
CODES
client.receive().then([](websocket_incoming_message msg) {
std::cout << "receiving data from socket";
// msg.message_type();
return msg.extract_string();
//1..i have one string
//cout<<"\n///////////test"<< msg.extract_string().get().c_str();
// // 2.convert to json array
//json::value::parse( ::to_string_t(msg.extract_string().get()))
//
}).then([](std::string body) {
//std::cout << "displaying the data";
std::cout << body << std::endl;
std::string ss = body;
ptree pt;
std::istringstream is(ss);
read_json(is, pt);
std::cout <<"\n 1st"<< "action: " << pt.get<std::string>("action") << "\n";
std::cout <<"\n 2nd"<< "data: " << pt.get<std::string>("data") << "\n";
std::cout << "--------------------------------------------------------------";
for (auto& e : pt.get_child("users_list")) {
std::cout << "\n" << "users list " << e.second.get<std::string>("user_id") << "\n";
}
});
useful resources
Parse JSON array as std::string with Boost ptree
C++ boost parse dynamically generated json string (not a file)
Related
I am trying to find a way to convert JSON string to XML document. For this we have evaluated PICOJSON to parse JSON and Pugixml to generate the XML document.
I know this is way easy in .Net and JAVA. My JSON is dynamic and based on the dynamic JSON I have to convert to XML.
I need some starting help on how to achieve this. Below code is sample to Parse JSON
#include <iostream>
#include "include/picojson.h";
#include "include/pugixml.hpp";
using namespace std;
int main() {
const char* json =
"{\"menu\": {"
"\"id\": \"f\","
"\"popup\": {"
" \"menuitem\": ["
" {\"v\": \"0\"},"
" {\"v\": \"1\"},"
" {\"v\": \"2\"}"
" ]"
" }"
"}"
"}";
picojson::value v;
std::string err;
const char* json_end = picojson::parse(v, json, json + strlen(json), &err);
}
I think the initial approach would be to covert JSON String to JSON object(Not sure how to do that) and then recursively construct XML
Will the below code convert JSON string to Object ?
picojson::parse(v, json, json + strlen(json), &err);
if (!err.empty()) {
std::cerr << err << std::endl;
}
Can someone guide me with initial code on how to do it, how to construct XML from JSON ?
If you're willing to use RapidJSON instead, you can make a SAX parser based on this example and map each JSON read event to an homologous XML write operation.
Hint: this probably means keeping a pugi::xml_node currentNode somewhere to keep track of the current node being worked on.
Edit
It seems POCO has SAX-like handlers after all, so you won't even need RapidJSON for this.
And if you want to minimize your dependencies, you can also use POCO.XML instead of pugixml.
Currently I have a JSON file (Test.json) with some valid data in json format and i'am trying to parse the data using a json object (readData) using JsonCpp, as below
Json::Value readData;
std::ifstream readFile("Test.json");
readFile >> readData;
This works fine if the json file is having valid contents in json format, but it crashes at "readFile >> readData" if the contents are not of a json format.
is there any way to validate the file before assigning it to a json object in C++ ?
It doesn't "crash"; it throws an exception. I'd guess you're not catching that exception.
Anyway, for reading JSON you probably want to use parseFromStream. This allows you to set options, and returns true or false. The operator>> you're using is just a shortcut.
Please read documentation for the functions that you use. It's there to help you.
I think you should use this code instead. It will not crash the program. It will just show you (on STDERR) what error has occurred.
Json::Value readData;
std::ifstream readFile("Test.json");
if (readFile) {
try {
readFile >> readData;
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
}
}
else {
std::cerr << "File not found!" << std::endl;
}
According to the documentation of JsonCpp, operator>>() results in std::exception on parse error.
I recently included a redis connection into one of my c++ programs. I decided to use the redox library since it seemed easy to use and does not depend on the boost library.
I use the connection to insert a value into a list in redis. The command works most of the times, but sometimes I get an error message saying that Received reply of type 3, expected type 1 or 5. After extensive search, I found these return types in the hiredis.h header file. It seems like the library expects a String or Status reply type but receives an Integer type.
Unfortunately I was not yet able to find any information about what this means and how I can fix the problem. Especially the fact that the codes sometimes works and sometimes does not confuses me.
In my use case I insert a string value containing a json dictionary in celery format (but essentially just a string) into a list. I am pretty sure that it has nothing to do with the way the string is composed as inserting the same string by hand via the redis-cli client works fine.
My code for inserting the message is:
redox::Redox rdx;
try {
if(!rdx.connect("localhost", 6379)){
cerr << "Could not connect to redis" << endl;
}
redox::Command<string>& c = rdx.commandSync<string>({"lpush", "queue_name", message});
if(!c.ok()) {
cerr << "Error while communicating with redis" << c.status() << endl;
}
} catch (runtime_error& e) {
cerr << "send_message: Exception in redox: " << e.what() << endl;
}
The error that is printed is the one after the !c.ok() check.
Thank you for your help.
The problem that you have is due to the fact that you use string as parameter to the response.
As mentioned in the documentation of redox:
This statement tells redox to run the command GET hello. The <string> template parameter means that we want the reply to be put into a string and that we expect the server to respond with something that can be put into a string
But that works because the example was using the "GET" command which is expected to return a string. In the case of the "LPUSH" command that you are using the return result is an integer as can be seen when issuing the command using redis-cli
127.0.0.1:6379> lpush "test" test
(integer) 1
So you must use a response with an integer parameter, the complete list of the possible response as listed here is:
<redisReply*>: All reply types, returns the hiredis struct directly
<char*>: Simple Strings, Bulk Strings
<std::string>: Simple Strings, Bulk Strings
<long long int>: Integers
<int>: Integers (careful about overflow, long long int recommended)
<std::nullptr_t>: Null Bulk Strings, any other receiving a nil reply will get a NIL_REPLY status
<std::vector<std::string>>: Arrays of Simple Strings or Bulk Strings (in received order)
<std::set<std::string>>: Arrays of Simple Strings or Bulk Strings (in sorted order)
<std::unordered_set<std::string>>: Arrays of Simple Strings or Bulk Strings (in no order)
So something like this would do:
redox::Redox rdx;
try {
if(!rdx.connect("localhost", 6379)){
cerr << "Could not connect to redis" << endl;
}
redox::Command<int>& c = rdx.commandSync<int>({"lpush", "queue_name", message});
if(!c.ok()) {
cerr << "Error while communicating with redis" << c.status() << endl;
}}catch (runtime_error& e) {
cerr << "send_message: Exception in redox: " << e.what() << endl;
}
Or if using a lamda:
redox::Redox rdx;
try {
if(!rdx.connect("localhost", 6379)){
cerr << "Could not connect to redis" << endl;
}
rdx.commandSync<int>(
{"lpush", "queue_name", message},
[](redox::Command<int>& response){
if(!response.ok()){
cerr << "Error while communicating with redis" << c.status() << endl;
}});
}catch (runtime_error& e) {
cerr << "send_message: Exception in redox: " << e.what() << endl;
}
cgicc can process form elements quite well , but how can i know whether the data is generated from get_method or post_method?
the piece of code i used:
cout << "Content-type:text/html\r\n\r\n";
try {
Cgicc cgi;
const_form_iterator iter;
for(iter = cgi.getElements().begin();
iter != cgi.getElements().end();
++iter){
cout <<
"<table><tr>" <<
"<td>" << iter->getName() << "</td>" <<
"<td>" << iter->getValue() << "</td>" <<
"</tr></table>" << endl;
}
}catch(exception& e) {
cout << e.what() << endl;
}
update:
i find this from the cgicc official page: "Parses both GET and POST form data transparently." (http://www.gnu.org/software/cgicc/)
it seems that cgicc don't want to separate get and post by design?
You can find the HTTP method (ì.e. GET, POST, etc...) of a request using cgicc::CgiEnvironment::getRequestMethod
I think the only way to solve it is by checking whether there is a variable name in the GET method query string that's the same name of the one in the POST method. This means that the variable name must be mentioned ONLY ONCE either of the two methods. In other words, if you combine the variables of the GET method with the variables of the POST in a single set, the variable name must be mentioned once in this set.
I am trying to send a Google Protocol Buffer serialized string across an HTTP connection and receive it back ( unmodified ) where I will deserialize it. My problem seems to be with the 'serializeToString' method which takes my string and seems to add newline characters ( and maybe other whitespace ) to the serialized string. In the example below, I am taking the string "camera_stuff" and after serializing it I get a QString with newlines at the front. I have tried other strings with the same result only with different whitespace and newlines added. This causes problems for my deserializing operation as the whitespace is not captured in the HTTP request and so the response containing the serialized string from the server cannot be successfully decoded. I can partially decode it if I guess the whitespace in the serialized string. How can I solve this? Please see the following code - thanks.
I have a protocol buffer .proto file that looks like:
message myInfo {
required string data = 1;
required int32 number = 2;
}
After running the protoc compiler, I construct in it Qt like this:
// Now Construct our Protocol Buffer Data to Send
myInfo testData;
testData.set_data("camera_stuff");
testData.set_number(123456789);
I serialize my data to a string like this:
// Serialize the protocol buffer to a string
std::string serializedProtocolData; // Create a standard string to serialize the protocol buffer contents to
myInfo.SerializeToString(&serializedProtocolData); // Serialize the contents to the string
QString serializedProtocolDataAsQString = QString::fromStdString(serializedProtocolData);
And then I print it out like this:
// Print what we are sending
qDebug() << "Sending Serialized String: " << serializedProtocolDataAsQString;
qDebug() << "Sending Serialized String (ASCII): " << serializedProtocolDataAsQString.toAscii();
qDebug() << "Sending Serialized String (UTF8): " << serializedProtocolDataAsQString.toUtf8();
qDebug() << "Sending Serialized Protocol Buffer";
qDebug() << "Data Number: " << QString::fromStdString(myInfo.data());
qDebug() << "Number: " << (int)myInfo.number();
When I send my data as part of an HTTP multipart message I see those print statements like this ( notice the newlines in the printouts! ):
Composing multipart message...
Sending Serialized String: "
camera_stuffï:"
Sending Serialized String (ASCII): "
camera_stuffï:"
Sending Serialized String (UTF8): "
camera_stuffÂÂï:"
Sending Serialized Protocol Buffer
Data: "camera_stuff"
Number: 123456789
Length of Protocol Buffer serialized message: 22
Loading complete...
The client deserializes the message like this:
// Now deserialize the protocol buffer
string = "\n\n" + string; // Notice that if I don't add the newlines I get nothing!
myInfo protocolBuffer;
protocolBuffer.ParseFromString(string.toStdString().c_str());
std::cout << "DATA: " << protocolBuffer.model() << std::endl;
std::cout << "NUMBER: " << protocolBuffer.serial() << std::endl;
qDebug() << "Received Serialized String: " << string;
qDebug() << "Received Deserialized Protocol Buffer";
qDebug() << "Data: " << QString::fromStdString(protocolBuffer.data());
qDebug() << "Number: " << (int)protocolBuffer.number();
The server gives it back without doing anything to the serialized string and the client prints the following:
RESPONSE: "camera_stuffï:"
DATA: camera_stu
NUMBER: 0
Received Serialized String: "
camera_stuffï:"
Received Deserialized Protocol Buffer
Number: "camera_stu"
Number: 0
So you see the issue is that I cannot guess the whitespace so I cannot seem to reliably deserialize my string. Any thoughts?
A serialized protobuf cannot be treated as a C string because it probably has embedded NULs in it. It's a binary protocol which uses every possible octet value and can only be sent over an 8-bit clean connection. It's also not a valid UTF-8 sequence, and cannot be serialized and deserialized as Unicode. So QString is also not a valid way of storing a serialized protobuf, and I suspect that might be causing you problems as well.
You can use std::string and QByteArray. I strongly suggest you avoid anything else. In particular, this is wrong:
protocolBuffer.ParseFromString(string.toStdString().c_str());
because it will truncate the protobuf at the first NUL. (Your test message doesn't have any, but this will bite you sooner or later.)
As for sending the message over HTTP, you need to be able to ensure that all bytes in the message are sent as-is, which also means that you need to send the length explicitly. You didn't include the code which actually transmits and receives the message, so I can't comment on it (and I don't know the Qt HTTP library well enough in any event), but the fact that 0x0A are being deleted from the front of the message suggests that you are missing something. Make sure you set the content-type in the message part correctly (not text, for example).