Add values to map using rapidjson - c++

I get a raw json string
{"vehicle": {"brand": "zonda","color": "blue"},"username": {"brand": "doyota","color": "red"}}
from a get call i make.
I read that rapidjson is the best way to parse a json string in cpp.
So I tried doing something like this:
const char* json = data.c_str();
rapidjson::Document document;
if (document.Parse(json).HasParseError()) {
cout << "has parse error" << endl;
return 1;
}
else {
assert(document.IsObject());
}
Here it says that the json has a parse error. Any idea why this could be?
Also once I am able to parse the values I want to add them as key value pairs to a standard map. Could anyone point me in the right direction to proceed with this?

This gave me no error:
#include <iostream>
#include "rapidjson/document.h"
#include "rapidjson/error/en.h"
using namespace rapidjson;
int main() {
Document d;
std::string json = R"raw({"vehicle": {"brand": "zonda","color": "blue"},"username": {"brand": "doyota","color": "red"}})raw";
if (d.Parse(json.c_str()).HasParseError()) {
std::cout << "has error\n";
} else {
std::cout << "no error\n";
}
}
Tried C++11 - C++20 and it all seems fine. My guess is that you've got some non UTF8 character in the data.

Related

XPath query returns a null node in a legacy C++ system using Xerces-C++ and Xalan-C++

I have been maintaining a legacy system that uses Xerces-C++ for XML parsing. I have to use Xalan-C++ to achieve full XPath support. I am using Xerces-C++ 3.2.3 and Xalan-C++ 1.12.0 - these versions are compatible with each other
I have been having issues with some code that I wrote based on this example guide: http://www.xatlantis.ch/index.php/blog/19-xml/26-x-path-with-xerces-and-xalan
I have checked other examples, but the above example is the only one I found that uses the XercesDOMParser wrapper. Other examples (including the one provided by Xalan-C++) use Xalan's own DOM implementation. I could technically use that as a very last resort, but I would very much prefer to use the Xerces DOM wrapper.
Here is a snippet of my code:
std::string xpath = "/some/path/with/namespaces";
const xalanc::XalanDOMString strExpression(xpath.c_str());
xercesc::DOMDocument* document = xml.parser().get().getDocument();
xercesc::DOMNode* root = document->getDocumentElement();
xalanc::XercesParserLiaison parserLiaison;
parserLiaison.setBuildWrapperNodes(true);
parserLiaison.setBuildMaps(true);
xalanc::XalanDocument* xalanDocument = parserLiaison.createDocument(document, false, false);
xalanc::XalanElement* documentElement = xalanDocument->getDocumentElement();
xalanc::XercesDocumentWrapper* xercesDocumentWrapper = parserLiaison.mapDocumentToWrapper(xalanDocument);
xalanc::XalanNode* rootContextNode = xercesDocumentWrapper->mapNode(root);
xalanc::XercesDOMSupport domSupport(parserLiaison);
if(rootContextNode != NULL) {
xalanc::XPathEvaluator evaluator;
xalanc::XalanNode* foundXalanNode = evaluator.selectSingleNode(
domSupport,
rootContextNode,
strExpression.c_str(),
documentElement);
xercesc::DOMNode* targetNode = NULL;
if(foundXalanNode != NULL) {
xercesc::DOMNode const* constTargetNode = xercesDocumentWrapper->mapNode(foundXalanNode);
targetNode = const_cast<xercesc::DOMNode*>(constTargetNode);
std::cout << "value: " << targetNode->getNodeValue() << std::endl;
}
}
This is the smallest snippet of code I could write to reproduce my problem, I apologise if it feels too big. Let me know if you need clarification on any part of it.
This code compiles successfully, but it does not output anything and it should output the value of an input element. Under further investigation, it seems that foundXalanNode is NULL, which tells me that the code is unable to find a node that matches my xpath. I tested the xpath expression I am using in an online browser, and it is correct. I also tested different variations of the xpath without namespaces.
Edit:
As requested, here is an example XML:
<?xml version="1.0" ?>
<ns3:header created="2022-04-07T14:19:55.611+01:00" schemaVersion="1.0.0" xmlns="example.org" xmlns:ns2="example.org" xmlns:ns3="example.org">
<ns3:point schemaVersion="1.1.0">
<ns2:type>PRODUCTION</ns2:type>
</ns3:point>
</ns3:header>
and here is the XPath I have been testing it with:
/ns3:header/ns3:point/ns2:type
I have tried to adapt the sample I mentioned in the comment to incorporate a Xerces DOM document and have Xalan wrap it; then I have run it against your sample XML with the arguments sample.xml / /ns3:header/ns3:point/ns2:type and the output is e.g. content: PRODUCTION, meaning the node is found.
The code is
#include <xalanc/Include/PlatformDefinitions.hpp>
#include <cassert>
#include <iostream>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/framework/LocalFileInputSource.hpp>
#include <xalanc/PlatformSupport/XSLException.hpp>
#include <xalanc/DOMSupport/XalanDocumentPrefixResolver.hpp>
#include <xalanc/XPath/XObject.hpp>
#include <xalanc/XPath/XPathEvaluator.hpp>
#include <xalanc/XalanSourceTree/XalanSourceTreeDOMSupport.hpp>
#include <xalanc/XalanSourceTree/XalanSourceTreeInit.hpp>
#include <xalanc/XalanSourceTree/XalanSourceTreeParserLiaison.hpp>
//#include <parser.h>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xalanc/XercesParserLiaison/XercesDocumentWrapper.hpp>
using namespace XERCES_CPP_NAMESPACE;
int
main(
int argc,
char* argv[])
{
using std::cerr;
using std::cout;
using std::endl;
int theResult = 0;
if (argc != 4)
{
cerr << "Usage: SimpleXPathAPI XMLFilePath Context XPathExpression" << endl;
theResult = -1;
}
else
{
using xalanc::XSLException;
try
{
using xercesc::XMLPlatformUtils;
using xalanc::XPathEvaluator;
XMLPlatformUtils::Initialize();
XPathEvaluator::initialize();
{
using xercesc::LocalFileInputSource;
using xalanc::XalanDocument;
using xalanc::XalanDocumentPrefixResolver;
using xalanc::XalanDOMString;
using xalanc::XalanNode;
//using xalanc::XalanSourceTreeInit;
//using xalanc::XalanSourceTreeDOMSupport;
//using xalanc::XalanSourceTreeParserLiaison;
using xalanc::XObjectPtr;
XercesDOMParser* parser = new XercesDOMParser;
parser->setDoNamespaces(true);
parser->parse(argv[1]);
DOMDocument* doc = parser->getDocument();
xalanc::XercesParserLiaison parserLiaison;
parserLiaison.setBuildWrapperNodes(true);
parserLiaison.setBuildMaps(true);
xalanc::XercesDOMSupport domSupport(parserLiaison);
// Initialize the XalanSourceTree subsystem...
//XalanSourceTreeInit theSourceTreeInit;
// We'll use these to parse the XML file.
//XalanSourceTreeDOMSupport theDOMSupport;
//XalanSourceTreeParserLiaison theLiaison(theDOMSupport);
// Hook the two together...
//theDOMSupport.setParserLiaison(&theLiaison);
//const XalanDOMString theFileName(argv[1]);
// Create an input source that represents a local file...
//const LocalFileInputSource theInputSource(theFileName.c_str());
// Parse the document...
XalanDocument* const theDocument = parserLiaison.createDocument(doc, false, false);
//theLiaison.parseXMLStream(theInputSource);
assert(theDocument != 0);
xalanc::XercesDocumentWrapper* xercesDocumentWrapper = parserLiaison.mapDocumentToWrapper(theDocument);
XalanDocumentPrefixResolver thePrefixResolver(theDocument);
XPathEvaluator theEvaluator;
// OK, let's find the context node...
XalanNode* const theContextNode =
theEvaluator.selectSingleNode(
domSupport,
theDocument,
XalanDOMString(argv[2]).c_str(),
thePrefixResolver);
if (theContextNode == 0)
{
cerr << "Warning -- No nodes matched the location path \""
<< argv[2]
<< "\"."
<< endl
<< "Execution cannot continue..."
<< endl
<< endl;
}
else
{
xalanc::XPathEvaluator evaluator;
xalanc::XalanNode* foundXalanNode = theEvaluator.selectSingleNode(
domSupport,
theContextNode,
XalanDOMString(argv[3]).c_str(),
thePrefixResolver);
xercesc::DOMNode* targetNode = NULL;
if (foundXalanNode != NULL) {
xercesc::DOMNode const* constTargetNode = xercesDocumentWrapper->mapNode(foundXalanNode);
targetNode = const_cast<xercesc::DOMNode*>(constTargetNode);
std::cout << "content: " << XMLString::transcode(targetNode->getTextContent(), XMLPlatformUtils::fgMemoryManager) << std::endl;
}
}
}
XPathEvaluator::terminate();
XMLPlatformUtils::Terminate();
}
catch(const XSLException& theException)
{
using xalanc::XalanDOMString;
XalanDOMString theError;
cerr << "XSL exception: "
<< theException.defaultFormat(theError)
<< endl;
theResult = -1;
}
catch(...)
{
cerr << "Generic exception caught!" << endl;
theResult = -1;
}
}
return theResult;
}
I have used Xalan 1.12 and Xerces 3.2.3. No idea where your approach fails but hopefully the above helps you on your way to get your Xalan XPath evaluation against a Xerces DOM working.

Boost::JSON, parsing string

So this is my JSON:
string js = R"({"table":"orderBookL2_25","action":"insert","data":[{"symbol":"XBTUSD","id":8796514950,"side":"Buy","size":10000,"price":34850.5},{"symbol":"XBTUSD","id":8796515700,"side":"Buy","size":281,"price":34843}]})";
I want to somehow convert it into object that could help me to conveniently access values. For example, something like that;
parsed_data["data"][0]["symbol"]
I have tried to use JSON::Boost but I don't know how to parse using this library. I have tried this code:
json::value parsed_data{js}; cout << parsed_data.at(0);
But the output from it is worthless:
"{\"table\":\"orderBookL2_25\",\"action\":\"insert\",\"data\":[{\"symbol\":\"XBTUSD\",\"id\":8796514950,\"side\":\"Buy\",\"size\":10000,\"price\":34850.5},{\"symbol\":\"XBTUSD\",\"id\":8796515700,\"side\":\"Buy\",\"size\":281,\"price\":34843}]}"
Basically your code (which you showed in fuzzy way) assigned string to JSon value object, that is why some signs has been escaped.
Problem is that you do not read documentation.
Please read JSon quick look note section how to parse input:
Quick Look - 1.75.0
Parsing
JSON can be parsed into the value container in one step using a free function. In the following snippet, a parse error is indicated by a thrown exception:
value jv = parse( "[1, 2, 3]" );
Error codes are also possible:
error_code ec;
value jv = parse( R"( "Hello, world!" )", ec );
Then fix code for example like this:
#include <iostream>
#include <vector>
#define BOOST_JSON_STACK_BUFFER_SIZE 1024
#include <boost/json/src.hpp>
#include <boost/json.hpp>
using namespace boost::json;
int main()
{
std::string js = R"({
"table":"orderBookL2_25",
"action":"insert",
"data":[
{
"symbol":"XBTUSD",
"id":8796514950,
"side":"Buy",
"size":10000,
"price":34850.5
},
{
"symbol":"XBTUSD",
"id":8796515700,
"side":"Buy",
"size":281,
"price":34843
}
]
})";
try {
auto parsed_data = parse(js);
std::cout << value_to<std::string>(parsed_data.at("data").at(0).at("symbol")) << '\n';
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
return 0;
}
Live demo

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;
}

Error handling in protobuf

I am new to protobuf (C++) and try to write first test program with protobuf.
Code is
#include <cstdlib>
#include <iostream>
#include "proto/req.pb.h"
using namespace std;
using namespace google::protobuf;
int main(int argc, char** argv) {
std::string s = "asdfasdf";
auto MyLogHandler = [] (google::protobuf::LogLevel level, const char* filename, int line, const std::string& message)
{
std::cout << "message " << message << std::endl;
};
google::protobuf::SetLogHandler(MyLogHandler);
Request req;
if ( req.ParseFromString(s)){
cout << "Parse - OK" << endl;
}else{
cout << "Parse - ERROR" << endl;
}
return 0;
}
When program runs - it show only error message, but not any reason about it. How can I get a reason for the error?
There are two reasons Protobuf parsing can fail:
The input data is missing required fields. In this case the Protobuf library writes a log message describing the problem and then returns false. Your log handler will receive the error message in this case.
The input data is not a valid Protobuf (it is corrupt, or was never a protobuf in the first place). In this case the Protobuf library simply returns false without any error message. There is really no useful information that the library could provide here. If this happens to you, the best way to debug is to dump the exact bytes right after you serialized the message and right before you parsed it, then look for differences.