C++REST SDK, parse JSON that contains (0xEF 0xBF 0xBF) character - c++

I have a REST API that returns a string with files metadata. Among those files I have one that has "￿" (0xEF0xBF0xBF, link) character in name. When I try to parse such a response I get exception that says:
e = {_message="* Line 1, Column 13 Syntax error: Malformed string literal" }
This is the string I'm trying to parse:
{"files":[["Thunderbolt ￿Gigabit￿ Ethernet ￿Adapter.txt",["bc288518-c426-4dbd-9600-a213a35d1c04",1447772221866,9,"Bartosz","Siewior"]],["System.Windows.Interactivity.dll",["56ce759b-019b-4723-8fca-7af877908971",1440507238241,55904,"Bartosz","Siewior"]]],"folderPermission":[["MODIFY"]],"directories":[]}
The code I'm using to receive and parse the string:
// ...
client.request(request).then([&](web::http::http_response response) {
status_code = response.status_code();
//response.extract_json(true).then([&](pplx::task<web::json::value> previousTask) {
response.extract_string().then([&](pplx::task<utility::string_t> previousTask) {
try {
utility::string_t str_response = previousTask.get();
web::json::value root;
root = web::json::value::parse(str_response);
}
catch (const web::http::http_exception& e) {
std::wstringstream ss;
ss << e.what();
str_response = ss.str();
}
catch (const web::json::json_exception& e) {
std::wstringstream ss;
ss << e.what();
str_response = ss.str();
}
TaskExecutionData data = { task.id, status_code, str_response.c_str() };
callback(data);
}).wait();
}).wait();
VS2013 JSON Visualizer can parse and show the result properly: VS_json_visualizer
I've tried C++REST version 2.5.0 and 2.6.0, neither of them is able to parse that string... Do you have any ides?

Answer from Casablanca's team:
The issue is that on windows we parse using UTF16 and the particular character you're having issues with maps to 0xFFFF. This is also the character returned by std::char_traits::eof(), so we detect the code point as an "end of stream" signal and terminate the parse appropriately.
The UTF8 parser should not have these issues, so as a workaround you can probably do something similar to how the current web::json::value::parse() function works in json_parsing.cpp:1245, except using char as the template parameter instead of utility::char_t.

Related

c++ JsonCpp parse string with escaped quotes as array

I've got the following json string:
{
"data" :
[
{
"cart" : "[{\"name\":\"Test item 1\",\"price\":15,\"quantity\":1,\"sum\":15,\"tax\":\"none\",\"payment_type\":\"advance\",\"item_type\":\"service\"},{\"name\":\"Test item 2\",\"price\":13.01,\"quantity\":2,\"sum\":26.02,\"tax\":\"none\",\"payment_type\":\"part_prepay\",\"item_type\":\"work\"}]",
"contact" : "noname#google.com",
"p_id" : "603",
"sum" : "100.02",
"tax_system" : "osn"
}
],
"msg" : null,
"result" : "success"
}
I can parse cart as std::string after parsing input json string as stringstream:
const std::string ParseJsonData(std::stringstream ssJsonStream)
{
Json::Value jsonData;
Json::Value responseData;
Json::Value responseDataCart;
Json::CharReaderBuilder jsonReader;
std::string errs;
if (Json::parseFromStream(jsonReader, ssJsonStream, &jsonData, &errs)) {
responseData = jsonData["data"];
responseDataCart = responseData[0]["cart"];
return responseDataCart.toStyledString().c_str();
}
else
return "Could not parse HTTP data as JSON";
}
Please, tell me, how can i parse cart as array with JsonCpp?
The same way you parsed the outer JSON!
You started with a string (well, hidden by a stream) and turned it into JSON.
Now that JSON contains a property that is a string and, itself, contains JSON. The problem is recursive. The fact that the inner string originally came from JSON too can be ignored. Just pretend it's a string you typed in.
So, you can use JSON::Reader to in turn get the JSON out of that string.
Something like:
const std::string responseDataCartStr = responseData[0]["cart"].asString();
Json::Reader reader;
if (!reader.parse(responseDataCartStr, responseDataCart))
throw std::runtime_error("Parsing nested JSON failed");
JsonCpp provides a few ways to parse JSON and it's worth exploring them to find the most appropriate for your use case. The above is just an example.
Ignore the backslashes — the escaping was meaningful within the encapsulating JSON document, but the outermost parse stage should already have taken that into consideration. You'll see if you print responseDataCartStr to console that it is a valid JSON document in its own right.

How to use Xerces to parse XML in a string [duplicate]

I know how to create a complete dom from an xml file just using XercesDOMParser:
xercesc::XercesDOMParser parser = new xercesc::XercesDOMParser();
parser->parse(path_to_my_file);
parser->getDocument(); // From here on I can access all nodes and do whatever i want
Well, that works... but what if I'd want to parse a string? Something like
std::string myxml = "<root>...</root>";
xercesc::XercesDOMParser parser = new xercesc::XercesDOMParser();
parser->parse(myxml);
parser->getDocument(); // From here on I can access all nodes and do whatever i want
I'm using version 3. Looking inside the AbstractDOMParser I see that parse method and its overloaded versions, only parse files.
How can I parse from a string?
Create a MemBufInputSource and parse that:
xercesc::MemBufInputSource myxml_buf(myxml.c_str(), myxml.size(),
"myxml (in memory)");
parser->parse(myxml_buf);
Use the following overload of XercesDOMParser::parse():
void XercesDOMParser::parse(const InputSource& source);
passing it a MemBufInputSource:
MemBufInputSource src((const XMLByte*)myxml.c_str(), myxml.length(), "dummy", false);
parser->parse(src);
Im doing it another way. If this is incorrect, please tell me why. It seems to work.
This is what parse expects:
DOMDocument* DOMLSParser::parse(const DOMLSInput * source )
So you need to put in a DOMLSInput instead of a an InputSource:
xercesc::DOMImplementation * impl = xercesc::DOMImplementation::getImplementation();
xercesc::DOMLSParser *parser = (xercesc::DOMImplementationLS*)impl)->createLSParser(xercesc::DOMImplementation::MODE_SYNCHRONOUS, 0);
xercesc::DOMDocument *doc;
xercesc::Wrapper4InputSource source (new xercesc::MemBufInputSource((const XMLByte *) (myxml.c_str()), myxml.size(), "A name");
parser->parse(&source);
You may use MemBufInputSource as found in the xercesc/framework/MemBufInputSource.cpp, and the header file, MemBufInputSource.hpp contains extensive documentation, as similar to answers above:
#include <xercesc/framework/MemBufInputSource.hpp>
char* myXMLBufString = "<root>hello xml</root>";
MemBufInputSource xmlBuf((const XMLByte*)myXMLBufString, 23, "myXMLBufName", false);
But take note, this doesn't seem to work unless you first initialize the system, as below (taken from the xerces-c-3.2.3/samples/src/SAX2Count/SAX2Count.cpp)
bool recognizeNEL = false;
char localeStr[64];
memset(localeStr, 0, sizeof localeStr);
// Initialize the XML4C2 system
try {
if (strlen(localeStr)) {
XMLPlatformUtils::Initialize(localeStr);
} else {
XMLPlatformUtils::Initialize();
}
if (recognizeNEL) {
XMLPlatformUtils::recognizeNEL(recognizeNEL);
}
} catch (const XMLException& toCatch) {
XERCES_STD_QUALIFIER cerr << "Error during initialization! Message:\n"
<< StrX(toCatch.getMessage()) << XERCES_STD_QUALIFIER endl;
return 1;
}
Of course reading a file wouldn't require thinking about this type of prep since you just pass a file path to the program which the parser takes. So for those experiencing seg faults, this could be the answer.

Not able to get values from JSON in Casablanca, C++

I'm using Casablanca, cpprestsdk to consume REST APIs in C++, in Visual Studio 2015 Professional. I'm trying to develop a simple example here hitting an API and parsing the response as JSON. The URL I'm using, actually returns all the parameters sent to the API.
I've hit the API and got response as well, extracted json from the response successfully. But when i try to read a value at any key from json, it crashes. Hence i put a check whether that key is available or not, and it always says json does not have the field. As an example i printed the data i.e. json. It has the key/field "name" but when i check it via has_field, it returns false.
Please help.
Complete code is below :
json::value postData;
postData[L"name"] = json::value::string(L"Joe Smith");
postData[L"sport"] = json::value::string(L"Baseball");
http_client client(L"https://httpbin.org/post);
http_request request(methods::POST);
request.set_body(postData);
client.request(request).then([](web::http::http_response response) {
json::value j = response.extract_json().get();
json::value data = j.at(U("data"));
std::wcout << "Json : " << data;
// Prints "{\"name\":\"Joe Smith\",\"sport\":\"Baseball\"}"
if (data.has_field(U("name"))) {
std::cout << "Name Found";
}
else {
std::cout << "Name key not Found";
}
});
It seems that your response looks like this:
{ "data": "{\"name\":\"Joe Smith\",\"sport\":\"Baseball\"}" }`
i.e. the actual data is not a JSon object but escaped JSon passed as string. I guess you need to return a payload that looks like this to do what you want to do the way you are doing it:
{
"data": {
"name": "John Smith",
"sport": "Baseball"
}
}

json serialize c++

I have this C++ code, and am having trouble json serializing it.
string uInput;
string const& retInput;
while(!std::cin.eof()) {
getline(cin, uInput);
JSONExample source; //JSON enabled class from jsonserialize.h
source.text = uInput;
//create JSON from producer
std::string json = JSON::producer<JSONExample>::convert(source); //string -> returns {"JSONExample":{"text":"hi"}}
//then create new instance from a consumer...
JSONExample sink = JSON::consumer<JSONExample>::convert(json);
//retInput = serialize(sink);
// Json::FastWriter fastWriter;
// retInput = fastWriter.write(uInput);
retInput = static_cast<string const&>(uInput);
pubnub::futres fr_2 = pb_2.publish(chan, retInput);
cout << "user input as json which should be published is " << retInput<< std::endl;
while(!cin.eof()) {
getline(cin, uInput);
newInput = "\"\\\"";
newInput += uInput;
newInput += "\\\"\"";
Instead of typing in the message like "\"hi\"", this code takes "hi" and does it.
If the change you described made the "Invalid JSON" disappear, then a "more correct" solution would be, AFAICT, to change the publish() line to:
pubnub::futres fr_2 = pb_2.publish(chan, json);
Because json already has JSON serialized data. Of course, if that JSON is what you want to publish.

Unable to parse XML after writing it Code Synthesis

After writing a XML using my project when i try to parse it using Codesynthesis
simulation_results sim_results;
try{
QString result_xml= "..\\XML\\My.xml";
sim_results =*simulation_results_(result_xml.toStdString(), xsd::cxx::tree::flags::dont_validate);
}
catch (const xml_schema::exception& e)
{
std::ostringstream os;
os << e;
std::string s = os.str ();
}
This parse fails,but if i try to parse this XML without changing it first everything is fine.
Bottom lines , when i first create it and then parse it fails.It is like is still open or need to be refreshed?