Prettify a JSON string in C++ from a .txt file - c++

I'm currently working in C++, getting an HTTP response from a request that I write into a .txt file using ostream. This happens asynchronously and I don't want to change this.
Once the data is done being written, I want to read from the file
{"data":{"request":[{"type":"City","query":"London, United Kingdom"}],"weather":[{"date":"2013-04-21","astronomy".....
~somehow~ prettify the string using either an outside library like nlohmann/json or other(?) and then
a)print it to the console and
b) save it in a different file (pretty.json)
I am having trouble understanding which method to use from:
https://github.com/nlohmann/json
Any ideas how to approach this?
I was thinking getting the file line by line until I hit EOF into a sort of "buffer" and then running _json on that and saving the solution which can be displayed on the console...
My code so far
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
#include <iostream>
#include <sstream>
#include "json.hpp"
using namespace utility; // string conversion
using namespace web; // URI
using namespace web::http; // HTTP commands
using namespace web::http::client; // HTTP Client features
using namespace concurrency::streams; // Asynch streams, like Node
using json = nlohmann::json;
int main()
{
auto fileStream = std::make_shared<ostream>();
// Open stream to output file.
pplx::task<void> requestTask = fstream::open_ostream(U("results.txt"))
.then([=](ostream outFile)
{
*fileStream = outFile;
http_client client //gets the info
return client.request(methods::GET, stringBuilder.to_string());
})
.then([=](http_response response) // set up response handler
{
printf("Received response status code:%u\n", response.status_code());
return response.body().read_to_end(fileStream->streambuf());
})
.then([=](size_t) // close file stream
{
return fileStream->close();
})
.then([=]()
{
nlohmann::json j;
std::ifstream i;
i.open("results.txt"); // ?? <<< === this is where my question is
});
// Wait for all the outstanding I/O to complete, handle exceptions
try
{
requestTask.wait();
}
catch (const std::exception &e)
{
printf("Error exception:%s\n", e.what());
}
return 0;
}
SOLUTION:
.then([=]()
{
// read a JSON file
std::ifstream readFromFile("results.txt");
if (readFromFile.is_open()) {
nlohmann::json j;
readFromFile >> j;
// write prettified JSON to another file
std::ofstream writeToFile("pretty.json");
writeToFile << std::setw(4) << j << std::endl;
readFromFile.close();
writeToFile.close();
}
else {
std::cout << "unable to open file";
}
});

You have two choices to prettify with nlohmann.
Uses dump which produces a string
int indent = 4;
nlohmann::json data;
data.dump(indent);
Or use the stream output overload with field width set
std::ofstream o("pretty.json");
o << std::setw(4) << data << std::endl;

Related

C++ How to parse JSON response using cppRest Library?

I am trying to parse JSON response using cppRest Library, but an exception is raised instead the JSON object, here is the error that is show below:
Incorrect Content-Type: must be textual to extract_string, JSON to extract_json.
And here is my code that I have tried so far:
#include <iostream>
#include <cpprest/http_client.h>
using namespace web::http;
using namespace web::http::client;
using namespace web;
using namespace std;
int main()
{
uri url(L"http://www.7timer.info/bin/astro.php?lon=113.2&lat=23.1&ac=0&unit=metric&output=json&tzshift=0");
http_client client(url);
http_response response;
http_request req;
req.set_method(methods::GET);
req.headers().set_content_type(L"application/json");
response = client.request(req).get();
try
{
json::object json_object(response.extract_json().get().as_object());
}
catch (exception &e)
{
cout << e.what() << "\n";
}
return 0;
}
I solved my problem, looks like I need to set the response headers to get the received content type as json:
Updated my code:
#include <iostream>
#include <cpprest/http_client.h>
using namespace web::http;
using namespace web::http::client;
using namespace web;
using namespace std;
int main()
{
uri url(L"http://www.7timer.info/bin/astro.php?lon=113.2&lat=23.1&ac=0&unit=metric&output=json&tzshift=0");
http_client client(url);
http_request req;
req.set_method(methods::GET);
pplx::task<json::value> requestTask = client.request(req).then([](http_response response)
{
json::value jsonObject;
try
{
if ( response.status_code() == status_codes::OK )
{
response.headers().set_content_type(L"application/json"); // Set headers to receive content type as JSON
jsonObject = response.extract_json().get();
}
}
catch (const http_exception& e)
{
cout << e.error_code().message() << "\n";
}
return jsonObject; // returned a json value
});
json::array dataseries = requestTask.get().at(L"dataseries").as_array(); // We get the returned response here
for (size_t i = 0; i < dataseries.size(); i++)
{
auto timepoint = dataseries[i].at(L"timepoint");
wcout << timepoint << endl;
}
return 0;
}

After convert string to const *json, when pasing json object, shows failed: (IsObject()), how to solve this?

After convert string strjson to const char* json, when interate, shows
failed: (IsObject()), function FindMember,failed, I don't understand why showed this, I think this the json object is correct format.
//
// main.cpp
// rapid
//
// Created by Shi Yan on 10/7/17.
// Copyright © 2017 Shi Yan. All rights reserved.
//
#include <iostream>
#include "rapidjson.h"
#include "document.h"
#include <fstream>
using namespace std;
using namespace rapidjson;
void readjson(){
ifstream handle("meta_Books.json");
if(handle.is_open()){
//cout<<"open success"<<endl;
const char* json;
string strjson;
int i=1;
while(getline(handle,strjson)){
if(i>4)
break;
cout<<strjson<<endl;
cout<<strjson.length()<<endl;
i++;
json=strjson.c_str();
cout<<"*********************"<<endl;
cout<<*json<<endl;
StringStream s (json);
Document document;
document.ParseStream(s);
Value::ConstMemberIterator itr = document.FindMember("asin");
cout<<itr->name.GetString()<<" = "<< itr->value.GetString()<<endl;
}
}
}
int main() {
readjson();
return 0;
}
I think the format of json object , so why failed?
As you can see , the getline() method works well, because the output of string is an complete string
The assertion error means that FindMember() is being called on a Value that does not represent a JSON object (IsObject() is false).
Since there is only 1 FindMember() in the code you showed, that implies that document.IsObject() is false when document.FindMember() fails. Either the JSON you are parsing does not start with an object in its root, or the parse failed. Neither condition of which you are testing for in your code.
If I had to guess (and please don't make people guess!), the failing JSON document likely contains an unencoded line break in it (that is not illegal inside of JSON string values). That would cause std::getline() to exit prematurely, thus causing parsing issues.
The 1st screenshot you showed supports that conclusion, showing that strjson is being split between 2 separate "lines" when the error occurs.
Rather than using std::getline() to read the file line-by-line, risking errors on embedded line breaks, I suggest you try using RapidJSON's BasicIStreamWrapper class to read the file document-by-document instead. ParseStream() has a kParseStopWhenDoneFlag flag that allows parsing multiple root documents from a single input stream:
kParseStopWhenDoneFlag 
After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.
For example:
#include <iostream>
#include <fstream>
#include "rapidjson.h"
#include "document.h"
#include "istreamwrapper.h"
using namespace std;
using namespace rapidjson;
void readjson()
{
ifstream handle("meta_Books.json");
if (!handle.is_open())
{
// handle error...
cout << "error opening file" << endl;
}
else
{
BasicIStreamWrapper<ifstream> s(handle);
for(int i = 1; i <= 4; ++i)
{
Document document;
ParseResult pr = document.ParseStream<kParseStopWhenDoneFlag>(s);
if (!pr)
{
// handle error...
cout << "error parsing document " << i << endl;
}
else if (!document.IsObject())
{
cout << "document " << i << " is not an object" << endl;
}
else
{
Value::ConstMemberIterator itr = document.FindMember("asin");
if (itr != document.MemberEnd())
cout << "asin = " << itr->value.GetString() << endl;
else
cout << "asin not found" << endl;
}
}
}
}
int main()
{
readjson();
return 0;
}

C++ Rest giving me an error when trying to show JSON file from web

I am trying to make a program that can display a JSON file in console with C++'s REST API. I'm trying to get the JSON file from api.trello.com but every example I come across gives me an error, usually about cbegin() & cend() and how it is not a value of web::json::value...
here is my code:
// The code includes the most frequently used includes necessary to work with C++ REST SDK
#include "cpprest/containerstream.h"
#include "cpprest/filestream.h"
#include "cpprest/http_client.h"
#include "cpprest/json.h"
#include "cpprest/producerconsumerstream.h"
#include <iostream>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
using namespace ::pplx;
using namespace utility;
using namespace concurrency::streams;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace web::json;
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
// Retrieves a JSON value from an HTTP request.
pplx::task<void> RequestJSONValueAsync()
{
// TODO: To successfully use this example, you must perform the request
// against a server that provides JSON data.
// This example fails because the returned Content-Type is text/html and not application/json.
http_client client(L"website.com/theRealURLContainsSecretKeys");
return client.request(methods::GET).then([](http_response response) -> pplx::task<json::value>
{
if (response.status_code() == status_codes::OK)
{
return response.extract_json();
}
// Handle error cases, for now return empty json value...
return pplx::task_from_result(json::value());
})
.then([](pplx::task<json::value> previousTask)
{
try
{
const json::value& v = previousTask.get();
// Perform actions here to process the JSON value...
}
catch (const http_exception& e)
{
// Print error.
wostringstream ss;
ss << e.what() << endl;
wcout << ss.str();
}
});
/* Output:
Content-Type must be application/json to extract (is: text/html)
*/
}
// Demonstrates how to iterate over a JSON object.
void IterateJSONValue()
{
// Create a JSON object.
json::value obj;
obj[L"key1"] = json::value::boolean(false);
obj[L"key2"] = json::value::number(44);
obj[L"key3"] = json::value::number(43.6);
obj[L"key4"] = json::value::string(U("str"));
// Loop over each element in the object.
for (auto iter = obj.cbegin(); iter != obj.cend(); ++iter)
{
// Make sure to get the value as const reference otherwise you will end up copying
// the whole JSON value recursively which can be expensive if it is a nested object.
const json::value &str = iter->first;
const json::value &v = iter->second;
// Perform actions here to process each string and value in the JSON object...
std::wcout << L"String: " << str.as_string() << L", Value: " << v.to_string() << endl;
}
/* Output:
String: key1, Value: false
String: key2, Value: 44
String: key3, Value: 43.6
String: key4, Value: str
*/
}
int wmain()
{
// This example uses the task::wait method to ensure that async operations complete before the app exits.
// In most apps, you typically don�t wait for async operations to complete.
wcout << L"Calling RequestJSONValueAsync..." << endl;
RequestJSONValueAsync().wait();
wcout << L"Calling IterateJSONValue..." << endl;
//IterateJSONValue();
system("pause");
}
I am having this error in VS 2015.
The only errors are in IterateJSONValue()
What is my problem and how can I fix it?
json::value does not contain a member function cbegin(). If you access obj.as_object() or obj.as_array() you will find your begin/end members.
// Loop over each element in the object.
for (const auto &pr : obj.as_object()) {
std::wcout << L"String: " << pr.first << L", Value: " << pr.second << endl;
}

cpprest client receive no response

when i build my own cpprestsdk server and client,i found that when my server receive a request and reply to it, my client have no reaction to it,and it never goes into the breakpoint where i handle the http_response,here is my code;
i was stuck for so many days,will someone help me fix this,thanks a lot
(client send request,server receives it and reply, client fail to receive http_response)
Server(i just got it from somewhere on internet):
#include "cpprest/json.h"
#include "cpprest/http_listener.h"
#include "cpprest/uri.h"
#include "cpprest/asyncrt_utils.h"
#include "cpprest/http_client.h"
using namespace web::http::experimental::listener;
using namespace web::http;
using namespace web;
void handle_get(http_request message)
{
message.reply(status_codes::OK, U("Hello, World!"));
};
void handle_post(http_request message)
{
message.reply(status_codes::NotFound);
};
void handle_put(http_request message)
{
message.reply(status_codes::NotFound);
};
void handle_delete(http_request message)
{
message.reply(status_codes::NotFound);
};
#define TRACE(msg) std::wcout << msg
#define TRACE_ACTION(a, k, v) std::wcout << a << L" (" << k << L", " << v << L")\n"
int main(int argc, char ** argv)
{
uri_builder uri(U("http://localhost:8888"));
http_listener listener(uri.to_uri());
listener.support(methods::GET, handle_get);
listener.support(methods::POST, handle_post);
listener.support(methods::PUT, handle_put);
listener.support(methods::DEL, handle_delete);
try
{
listener
.open()
.then([&listener](){TRACE(L"\nstarting to listen\n"); })
.wait();
while (true);
}
catch (std::exception const & e)
{
std::wcout << e.what() << std::endl;
}
catch (...)
{
std::wcout << "Unknown exception" << std::endl;
}
return 0;
}
and here is my Client
#include "cpprest/http_client.h"
#include "cpprest/filestream.h"
using namespace utility; // Common utilities like string conversions
using namespace web; // Common features like URIs.
using namespace web::http; // Common HTTP functionality
using namespace web::http::client; // HTTP client features
using namespace concurrency::streams; // Asynchronous streams
int main(int argc, char* argv[])
{
auto fileStream = std::make_shared<ostream>();
// Open stream to output file.
pplx::task<void> requestTask = fstream::open_ostream(U("results.html")).then([=](ostream outFile)
{
*fileStream = outFile;
// Create http_client to send the request.
http_client client(U("http://www.bing.com/"));
http_client localclient(U("http://localhost:8888"));
return localclient.request(methods::GET);
})
.then([=](http_response response)
{
printf("Received response status code:%u\n", response.status_code());
system("pause");
return response.body().read_to_end(fileStream->streambuf());
})
.then([=](size_t)
{
return fileStream->close();
});
try
{
requestTask.wait();
}
catch (const std::exception &e)
{
printf("Error exception:%s\n", e.what());
system("pause");
}
return 0;
}

How to read image content from an HTTP server response using Poco C++?

I am writing an HTTP client in C++ with Poco and there is a situation in which the server sends a response with a jpeg image content (in bytes). I need the client to process the response and generate a jpg image file from those bytes.
I searched the Poco library for appropriate functions but I haven't found any. It seems that the only way to do it is manually.
This is part of my code. It takes the response and makes the input stream start at the beginning of the image content.
/* Get response */
HTTPResponse res;
cout << res.getStatus() << " " << res.getReason() << endl;
istream &is = session.receiveResponse(res);
/* Download the image from the server */
char *s = NULL;
int length;
std::string slength;
for (;;) {
is.getline(s, '\n');
string line(s);
if (line.find("Content-Length:") < 0)
continue;
slength = line.substr(15);
slength = trim(slength);
stringstream(slength) >> length;
break;
}
/* Make `is` point to the beginning of the image content */
is.getline(s, '\n');
How to proceed?
Below is code to get the response body as a string. You could also write it directly to a file with ofstream (see below).
#include <iostream>
#include <sstream>
#include <string>
#include <Poco/Net/HTTPClientSession.h>
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/HTTPResponse.h>
#include <Poco/Net/Context.h>
#include <Poco/Net/SSLManager.h>
#include <Poco/StreamCopier.h>
#include <Poco/Path.h>
#include <Poco/URI.h>
#include <Poco/Exception.h>
ostringstream out_string_stream;
// send request
HTTPRequest request( HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1 );
session.sendRequest( request );
// get response
HTTPResponse response;
cout << response.getStatus() << " " << response.getReason() << endl;
// print response
istream &is = session.receiveResponse( response );
StreamCopier::copyStream( is, out_string_stream );
string response_body = out_string_stream.str();
To write directly to a file, you can use this:
// print response
istream &is = session->receiveResponse( response );
ofstream outfile;
outfile.open( "myfile.jpg" );
StreamCopier::copyStream( is, outfile );
outfile.close();