Parse json array string using jsoncpp - c++

I have this JSON:
[{"header": "test" , "test2" : "test2"}]
I'm trying to parse this using jsoncpp.
Here's my code snippet:
Json::CharReaderBuilder builder;
Json::CharReader *reader = builder.newCharReader();
Json::Value root;
bool parseRet = reader->parse(serverResponse.c_str(),serverResponse.c_str() +serverResponse.size(), &root, &errors);
parseRet returns true. But root does not include json data.
How do I parse this?

parseRet returns true. But root does not include JSON data.
This sounds like an issue with the way you're accessing the parsed JSON elements.
Below is a complete working example with a raw string literal as JSON input.
A few points:
Use std::unique_ptr for reader to de-allocate memory appropriately at the end. In your code snippet, it's a memory leak.
Read the documentation carefully! Accessing an element using a method or operator might return a default value or an exception so handle accordingly. For example, the JSON in root is an array so it should be accessed by index and then each index contains an object i.e. root[0]["header"].
Example (C++11):
#include <iostream>
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>
int main()
{
const std::string raw_json = R"json([{"header": "test" , "test2" : "test2"}])json";
Json::CharReaderBuilder builder {};
// Don't leak memory! Use std::unique_ptr!
auto reader = std::unique_ptr<Json::CharReader>( builder.newCharReader() );
Json::Value root {};
std::string errors {};
const auto is_parsed = reader->parse( raw_json.c_str(),
raw_json.c_str() + raw_json.length(),
&root,
&errors );
if ( !is_parsed )
{
std::cerr << "ERROR: Could not parse! " << errors << '\n';
return -1;
}
std::cout << "Parsed JSON:\n" << root << "\n\n";
try
{
std::cout << "header: " << root[0]["header"] << '\n';
std::cout << "test2 : " << root[0]["test2"] << '\n';
}
catch ( const Json::Exception& e )
{
std::cerr << e.what() << '\n';
}
return 0;
}
Output:
Parsed JSON:
[
{
"header" : "test",
"test2" : "test2"
}
]
header: "test"
test2 : "test2"

Related

Check for Element Existence in TinyXML

I have been looking through the API for TinyXML and I can't find a way to check if an element exists before I try and get it by name. I have commented what I am looking for below:
#include <iostream>
#include "tinyxml.h"
int main()
{
const char* exampleText = "<test>\
<field1>Test Me</field1>\
<field2>And Me</field2>\
</test>";
TiXmlDocument exampleDoc;
exampleDoc.Parse(exampleText);
// exampleDoc.hasChildElement("field1") { // Which doesn't exist
std::string result = exampleDoc.FirstChildElement("test")
->FirstChildElement("field1")
->GetText();
// }
std::cout << "The result is: " << result << std::endl;
}
The FirstChildElement function will return a pointer, so that pointer can be used in the if-statement like so.
#include <iostream>
#include "tinyxml.h"
int main()
{
const char* exampleText = "<test>\
<field1>Test Me</field1>\
<field2>And Me</field2>\
</test>";
TiXmlDocument exampleDoc;
exampleDoc.Parse(exampleText);
TiXmlElement* field1 = exampleDoc.FirstChildElement("test")
->FirstChildElement("field1");
if (field1) {
std::string result = field1->GetText();
std::cout << "The result is: " << result << std::endl;
}
}

boost ptree access first element with no path name

I am using boost library to manipulate a JSON string and I would like to access to a first element.
I was wondering if there where some convenient way to access a first element of ptree with no path name.
I do this, but I got no value :
namespace pt = boost::property_tree;
pt::ptree pt2;
string json = "\"ok\"";
istringstream is(json);
try
{
pt::read_json(is, pt2);
cout << pt2.get_child("").equal_range("").first->first.data() << endl;
}
catch (std::exception const& e)
{
cerr << e.what() << endl;
}
Solution:
replace cout << pt2.get_child("").equal_range("").first->first.data() << endl;
by cout << pt2.get_value<std::string>() << endl;
Firstly, Property Tree is not a JSON library.
Secondly, the input is not in the subset of JSON supported by the library (e.g.).
Thirdly, since the input results in a tree that has no child nodes, you should use the value of the root node itself.
Lastly, if you had wanted the first node, use ordered_begin()->second:
Live On Coliru
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <iostream>
void broken_input() {
boost::property_tree::ptree pt;
std::istringstream is("\"ok\"");
read_json(is, pt);
std::cout << "Root value is " << pt.get_value<std::string>() << std::endl;
}
void normal_tree() {
boost::property_tree::ptree pt;
pt.put("first", "hello");
pt.put("second", "world");
pt.put("third", "bye");
std::cout << pt.ordered_begin()->second.get_value<std::string>() << std::endl;
write_json(std::cout, pt);
}
int main() {
try {
broken_input();
normal_tree();
}
catch (std::exception const& e)
{
std::cerr << e.what() << std::endl;
}
}
Prints
Root value is ok
hello
{
"first": "hello",
"second": "world",
"third": "bye"
}
I would like to access to a first element.
It is impossible in general case, since JSON elements are not place-fixed by definition. The current first element can change its place after JSON transformations and a resulting JSON will be the same, although elements are reordered. Thus such API is not provided by BOOST.

MessagePack C++ - How to iterate through an unknown data structure?

I want to share structured data between C++ and Python languages using MessagePack like this one:
{
"t" : [ [t00,...,t0N], ... , [tM0,...,tMN] ],
"x" : [ x0,..,xN],
"P" : [ [P00, ..., P0N], ..., [PM0,...,PMN] ]
}
The number of variables is optional so in some cases I will have for example only:
{
"t" : [ [t00,...,t0N], ... , [tM0,...,tMN] ]
}
Decoding this in Python is pretty simple, my problem is to figure out
how to decode this in C++ if I don't know in advance the structure of
the data ? or the exact number of variables that I would have; is it
possible to iterate the structure in these cases?
I managed to handle a "fixed" data structure ( always with the same
number of variables ) defining a struct for example:
struct variables
{
std::vector< std::vector<double> > t;
std::vector< double > x;
std::vector< std::vector<double> > P;
MSPACK_DEFINE_MAP( t, x, P );
};
std::stringstream inBuffer;
.... (read data )
std::string str( inBuffer.str() );
msgpack::object_handle oh = msgpack::unpack( str.data(), str.size() );
msgpack::object deserialized = oh.get();
variables var;
deserialized.convert( var );
Is there a better way to accomplish this ?, how could manage optional
variables that could not appear in the structure ?; I repeat the
previous question: could I iterate an unknown data structure in C++?,
how ?
Thanks in advance!
Regards, Ernesto
There are two ways to treat unknown data structure.
The first way is using parse/visitor mechanism.
Here is an example:
#include <msgpack.hpp>
#include <sstream>
#include <iostream>
// This is a simple print example visitor.
// You can do any processing in your visitor.
struct my_visitor : msgpack::null_visitor {
bool start_map_key() {
processing_map_key = true;
return true;
}
bool end_map_key() {
processing_map_key = false;
return true;
}
bool start_array(uint32_t size) {
std::cout << "array (size:" << size << ")[" << std::endl;
return true;
}
bool end_array() {
std::cout << "]" << std::endl;
return true;
}
bool visit_str(const char* v, uint32_t size) {
if (processing_map_key) {
std::cout << "map key:" << std::string(v, size) << std::endl;
}
return true;
}
bool visit_positive_integer(uint64_t v) {
std::cout << "found value:" << v << std::endl;
return true;
}
bool processing_map_key = false;
std::string indent;
};
int main() {
// create test data
std::stringstream ss;
msgpack::packer<std::stringstream> pk(ss);
pk.pack_map(1);
pk.pack("t");
pk.pack_array(2);
pk.pack_array(3);
pk.pack(1);
pk.pack(2);
pk.pack(3);
pk.pack_array(3);
pk.pack(4);
pk.pack(5);
pk.pack(6);
// print data (for debug)
{
auto oh = msgpack::unpack(ss.str().data(), ss.str().size());
std::cout << oh.get() << std::endl;
}
// apply visitor
{
my_visitor mv;
msgpack::parse(ss.str().data(), ss.str().size(), mv);
}
}
Running demo: https://wandbox.org/permlink/3NrR4IMDIuLTk9e9
See https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_visitor.
The other way is using msgpack::type::variant or `msgpack::type::variant_ref.
The former copies data, you can update it. The latter doesn't copy data. You cannot update it.
This approach requires boost. So you need to define MSGPACK_USE_BOOST. I recommend defining as a compiler option.
// Boost is required
#define MSGPACK_USE_BOOST
#include <msgpack.hpp>
#include <sstream>
#include <iostream>
struct my_visitor:boost::static_visitor<void> {
void operator()(uint64_t v) const {
std::cout << "positive insteger:" << v << std::endl;
}
// const is required for map key because std::multimap's key (first) is const.
void operator()(std::string const& v) const {
std::cout << "string:" << v << std::endl;
}
void operator()(std::vector<msgpack::type::variant>& v) const {
std::cout << "array found" << std::endl;
for (auto& e : v) {
boost::apply_visitor(*this, e);
}
}
void operator()(std::multimap<msgpack::type::variant, msgpack::type::variant>& v) const {
std::cout << "map found" << std::endl;
for (auto& e : v) {
std::cout << "key:" << std::endl;
boost::apply_visitor(*this, e.first);
std::cout << "value:" << std::endl;
boost::apply_visitor(*this, e.second);
}
}
template <typename T>
void operator()(T const&) const {
std::cout << " match others" << std::endl;
}
};
int main() {
// create test data
std::stringstream ss;
msgpack::packer<std::stringstream> pk(ss);
pk.pack_map(1);
pk.pack("t");
pk.pack_array(2);
pk.pack_array(3);
pk.pack(1);
pk.pack(2);
pk.pack(3);
pk.pack_array(3);
pk.pack(4);
pk.pack(5);
pk.pack(6);
auto oh = msgpack::unpack(ss.str().data(), ss.str().size());
std::cout << oh.get() << std::endl;
msgpack::type::variant v = oh.get().as<msgpack::type::variant>();
boost::apply_visitor(my_visitor(), v);
}
Running demo: https://wandbox.org/permlink/HQwJjfwW8rLEMi0d
See https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_variant
Here are exampless:
https://github.com/msgpack/msgpack-c/blob/master/example/boost/msgpack_variant_capitalize.cpp
https://github.com/msgpack/msgpack-c/blob/master/example/boost/msgpack_variant_mapbased.cpp
Both ways can treat unpredictable data structure. You need to do some visitor processing. If the data structure is predictable some extent, your original approach is also good way.
Actually there is a simpler way, if you are dealing with maps (like stated in the question), not arrays.
msgpack::object_handle oh = msgpack::unpack(/* some data */);
std::map<std::string,msgpack::type::variant> map = obj.convert();
This way you will get a map with all the data, no need for a visitor or boost.

Trouble using get_value with Boost's property trees

I have to write an XML parser with Boost. However I have some trouble.
I can access the nodes name without any problem, but for some reason I can't access the attributes inside a tag by using get_value, which should work instantly. Maybe there is a mistake in my code I didn't spot? Take a look:
void ParametersGroup::load(const boost::property_tree::ptree &pt)
{
using boost::property_tree::ptree;
BOOST_FOREACH(const ptree::value_type& v, pt)
{
name = v.second.get_value<std::string>("name");
std::string node_name = v.first;
if (node_name == "<xmlattr>" || node_name == "<xmlcomment>")
continue;
else if (node_name == "ParametersGroup")
sg.load(v.second); // Recursion to go deeper
else if (node_name == "Parameter")
{
// Do stuff
std::cout << "PARAMETER_ELEM" << std::endl;
std::cout << "name: " << name << std::endl;
std::cout << "node_name: " << node_name << std::endl << std::endl;
}
else
{
std::cerr << "FATAL ERROR: XML document contains a non-recognized element: " << node_name << std::endl;
exit(-1);
}
}
}
So basically I ignore and tags, when I'm in a ParametersGroup tag I go deeper, and when I'm in a Parameter tag I recover the datas to do stuff. However, I can't get the "name" properly.
This is the kind of lines I'm scanning in the last else if :
<Parameter name="box">
The std::cout << name displays things like that:
name: ^M
^M
^M
^M
^M
^M
which is obvisouly not what I'm asking for.
What am I doing wrong? Any help would be greatly appreciated.
Since your question isn't particularly selfcontained, here's my selfcontained counter example:
Live On Coliru
#include <sstream>
#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
using namespace boost::property_tree;
int main() {
ptree pt;
std::istringstream iss("<Parameter name=\"box\" />");
xml_parser::read_xml(iss, pt);
for (auto& element : pt)
{
std::cout << "'" << element.first << "'\n";
for (auto& attr : element.second)
{
std::cout << "'" << attr.first << "'\n";
for (auto& which : attr.second)
{
std::cout << "'" << which.first << "': \"" << which.second.get_value<std::string>() << "\"\n";
}
}
}
}
It prints
'Parameter'
'<xmlattr>'
'name': "box"
I hope you can see what you need to do (likely an unexpected level of nodes in the tree?). To get directly to the leaf node:
pt.get_child("Parameter.<xmlattr>.name").get_value<std::string>()

Passing variable (array type) from function to "main" scope Type: std::tr1::match_results<std::string::const_iterator>

I would like to pass the variable from a function to the main scope which I'm calling, I'm trying to do like I use to do in C but it returns nothing.
I want to be able to output and deal with it after the return of the function
#include "StdAfx.h"
#include <regex>
#include <iostream>
#include <string>
#include <conio.h>
using namespace std;
std::tr1::match_results<std::string::const_iterator> match(std::string& regex, const std::string& ip,std::tr1::match_results<std::string::const_iterator> res)
{
const std::tr1::regex pattern(regex.c_str());
bool valid = std::tr1::regex_match(ip, res, pattern);
std::cout << ip << " \t: " << (valid ? "valid" : "invalid") << std::endl;
cout << "FIRST RES FOUND: " << res[1] << endl;
return res;
}
int main()
{
string regex = "(\\d{1,3}):(\\d{1,3}):(\\d{1,3}):(\\d{1,3})";
string ip = "49:22:33:444";
std::tr1::match_results<std::string::const_iterator> res;
match(regex,ip.c_str(), res);
cout << "Result >" << res[1] << "< " << endl;
_getch(); return 0;
}
When I compile and run, The output is: "FIRST RES FOUND: 49
Result ><"
It's probably a really simple solution but what do I have to do to set it for my main can read it correctly as in: "Result >49<"
Thanks in advance. :)
Option 1: Use references:
void match(string& regex, const string& ip, tr1::match_results<string::const_iterator> & res)
{
const tr1::regex pattern(regex.c_str());
bool valid = tr1::regex_match(ip, res, pattern);
cout << ip << " \t: " << (valid ? "valid" : "invalid") << endl;
cout << "FIRST RES FOUND: " << res[1] << endl;
}
Option 2: Return the result by value and store it:
tr1::match_results<string::const_iterator> match(string& regex, const string& ip)
{
tr1::match_results<string::const_iterator> res;
// ...
return res;
}
int main()
{
// ...
tr1::match_results<string::const_iterator> res = match(regex, ip);
}
On a separate note, there should be absolutely no need for all the c_str() calls, as <regex> has a perfectly functional std::string interface. Check the documentation for details, you just have to get a couple of typenames right.
Edit: Here are some basic examples on using std::string. There are equivalent constructions for std::wstring, char* and wchar_t*, but std::strings should be the most useful one.
Since <regex> support is still patchy, you should consider the TR1 and Boost alternatives, too; I provide all three and you can pick one:
namespace ns = std; // for <regex>
namespace ns = std::tr1; // for <tr1/regex>
namespace ns = boost; // for <boost/regex.hpp>
ns::regex r("");
ns::smatch rxres; // 's' for 'string'
std::string data = argv[1]; // the data to be matched
// Fun #1: Search once
if (!ns::regex_search(data, rxres, r))
{
std::cout << "No match." << std::endl;
return 0;
}
// Fun #2: Iterate over all matches
ns::sregex_iterator rt(data.begin(), data.end(), r), rend;
for ( ; rt != rend; ++rt)
{
// *rt is the entire match object
for (auto it = rt->begin(), end = rt->end(); it != end; ++it)
{
// *it is the current capture group; the first one is the entire match
std::cout << " Match[" << std::distance(rt->begin(), it) << "]: " << *it << ", length " << it->length() << std::endl;
}
}
Don't forget to handle exceptions of type ns::regex_error.
Pass in res by reference instead of by value. In other words, declare the parameter res as a reference instead of a value, i.e., type &res, not type res.