I need some help when iterating over JSON ptree in boost. Here's the structure.
{"drives": [{"busy": false, "eof": false, "density": 88 }]}
What I want to do is to print the key and value eg. busy = false. I've tried the code below but there is no output.
BOOST_FOREACH(ptree::value_type &v, pt.get_child("drives"))
{
cout << v.first << endl; // does not work
cout << v.second.data() << endl; // does not work
cout << v.second.get<string>("busy"); // works
}
So how do I print the key?
Thanks in advance for any help.
I went through some old code and I found the way
BOOST_FOREACH(ptree::value_type &v, pt.get_child("drives"))
{
for(auto iter = v.second.begin(); iter!= v.second.end(); ++iter)
{
std::cout << iter->first << " : " << iter->second.get_value<std::string>() << std::endl;
}
}
You only need to iterate over "drives" if you have more than one "drives", and in your json example you don't have.
In your code you try to print v.first and v.data() but those two doesn't hold the data you think they hold.
v.first supposed to hold the key name of "KeyName":{"busy": false, "eof": false, "density": 88 }
which doesn't exists because this value is part of an array.
the v.data() (If I'm not mistaken) holds the key:value which is an inner presentation and cannot be printed this way.
I really think you should try using a different framework for JSON.
Related
I have a fairly easy problem: I have an std::map<int,T> and another std::set<int> (can be std::vector or similar too).
In the map I store items, and in the other container I'm storing favorites (of the map).
At some point, I'd need to retrieve (all) items from the map, but starting with the favorites defined by the other container.
Here is my minimal repro, I solved it very ugly, and ineffective:
#include <iostream>
#include <string>
#include <set>
#include <map>
using namespace std;
map<int, string> myMap;
set<int> myFavorites;
int main()
{
myMap.emplace(1, "but I don't like this");
myMap.emplace(12, "So it will go below");
myMap.emplace(31, "This one will come first, and");
myMap.emplace(44, "under my favorites");
myMap.emplace(52, "then this will follow");
myFavorites.insert(52);
myFavorites.insert(31);
cout << "My map:" << endl;
for(auto p : myMap) {
cout << "#" << p.first << "=" << p.second << endl;
}
cout << endl << "My favorites:" << endl;
for(auto p : myFavorites) {
cout << "#" << p << endl;
}
cout << endl << "All items starting with my favorites:" << endl;
for(auto p : myFavorites) {
auto item = myMap.find(p);
if (item != myMap.end()) cout << "#" << item->first << "=" << item->second << endl;
}
for(auto p : myMap) {
if (myFavorites.find(p.first) != myFavorites.end()) continue;
cout << "#" << p.first << "=" << p.second << endl;
}
}
What really bothers me is the last loop, where each iterations would call find on the set.
Required output is:
All items starting with my favorites:
#31=This one will come first, and
#52=then this will follow
#1=but I don't like this
#12=So it will go below
#44=under my favorites
Here is the above source in Coliru for making it easier: https://coliru.stacked-crooked.com/a/731fa76d90bfab00
Both map and set might be changed, but replacements needs to implement the same interfaces as originals.
I'm looking for a way to solve this more efficient than my original "brute-force" one.
Please note: map must not be "reordered"! I just need to query (retrieve) its items with custom sorting!
Note2: I know map can have a comparison operator. But I'd need to have the original order usually, and sometimes I'd need to have the custom sort!
Note3: Boost is not available and compiler is C++14 capable.
Both std::map and std::set use the same strict weak ordering for ordering its contents.
You can take advantage of this. You know that if you iterate over the map you will get the keys in the same order as they are in the set, therefore all it takes is a little bit of clever logic, something like:
auto map_iter=myMap.begin();
for(auto p : myFavorites) {
while (map_iter != myMap.end())
{
if (map_iter->first == p)
cout << "#" << map_iter->first << "=" << map_iter->second << endl;
if (map_iter->first > p)
break;
++map_iter;
}
}
It may still make sense to use find() in some edge cases, specifically when myFavorites is significantly smaller than myMap, in which case a few calls to find() might be faster than iterating over (most of) the entire map.
File:
{
"somestring":{
"a":1,
"b":7,
"c":17,
"d":137,
"e":"Republic"
},
}
how can I read the somestring value by jsoncpp?
Use the getMemberNames() method.
Json::Value root;
root << jsonString;
Json::Value::Members propNames = root.getMemberNames();
std::string firstProp = propNames[0];
std::cout << firstProp << '\n'; // should print somestring
If you want to see all the properties, you can loop through it using an iterator:
for (auto it: propNames) {
cout << "Property: " << *it << " Value: " << root[*it].asString() << "\n";
}
This simple loop will only work for properties whose values are strings. If you want to handle nested objects, like in your example, you'll need to make it recursive, which I'm leaving as an exercise for the reader.
I'm a boost newbie.
How do I access the object from an iterator? I have something like:
boost::container::vector<std::string>::iterator plitr = myvec.begin();
while (plitr != myvec.end()){
std::cout << "data at index[" << plitr - myvec.begin() << "]: " << plitr->x <<std::endl;
plitr++;
}
But I realize that plitr->x does not exist nor am I sure if the index can be calculated the way I think.
Can anyone help?
The usage of boost::vector is identical to std::vector. Calculating the index hence works the way you showed, because the iterator fulfills random access criteria. Concerning access to the object, you want to dereference the iterator. Change your loop to
while (plitr != myvec.end()){
std::cout << "data at index[" << plitr - myvec.begin() << "]: " << *plitr <<std::endl;
plitr++;
}
and it will work (note the *plitr, that't the dereferencing part). Just as a side note, using a range based for loop to access every std::string in myvec might be more convenient here:
for (auto&& str : myvec)
std::cout << str << std::endl;
I've been working on a simple database system managment and I've come up with:
std::map< std::string, std::vector < std::map < std::string,
boost::variant <std::string, size_t, double bool> > > tables;
I have a map (tables) of vectors (table) of maps (records) and I've allready wrote a function to read a file to it but I'm not really sure how to access the single attributes.
I can print the whole thing with:
for(auto table: tables)
for(auto record : table.second)
for(auto attribute : record) {
std::cout << j.second;
I tried doing something like:
std::cout << tables["credentials"][2]["username"];
This however does not work; it only prints a blank line.
It's most likely that you are using wrong keys of the maps to access the database.
Update your code to print the contents of your database so you can see the keys also in the maps.
for(auto table: tables)
{
std::cout << "Key: " << table.first << std::endl;
for(auto record : table.second)
{
for(auto attribute : record)
{
std::cout << "Key: " << attribute.first
<< ", Value: " << attribute.second << std::endl;
}
}
}
I have a Playlist class that has a vector with Tracks and each Track has a multimap<long, Note> as datamember.
class Track {
private:
multimap<long, Note> noteList;
}
Using an iterator to acces the tracks is no problem, so this part here is working fine:
vector<Track>::iterator trackIT;
try{
for(noteIT = trackIT->getNoteList().begin(); noteIT != trackIT->getNoteList().end(); noteIT++){
cout << "---" << noteIT->second.getName() << endl;
}
}catch (int e){
cout << "exception #" << e << endl;
}
What I want to do next is iterate the Notes of each Track. But starting from this part all output is stopped. So I only get to see the first tracks name. Any cout's after that are not shown and the compiler isn't giving me any errors. Even the cout inside the try catch block isn't working..
vector<Track>::iterator trackIT;
multimap<long, Note>::iterator noteIT;
for(trackIT = this->playlist.getTracklist().begin(); trackIT < this->playlist.getTracklist().end(); trackIT++){
cout << trackIT->getTrackName() << endl;
for(noteIT = trackIT->getNoteList().begin(); noteIT != trackIT->getNoteList().end(); noteIT++){
cout << "---" << noteIT->second.getName() << endl;
}
}
cout << "random cout that is NOT shown" << endl; // this part doesn't show up in console either
Also, the method in my Track class that I'm using to add the Note objects looks like this:
void Track::addNote(Note ¬e) {
long key = 1000009;
this->noteList.insert(make_pair(key, note));
}
// I'm adding the notes to the track like this:
Note note1(440, 100, 8, 1, 1);
note1.setName("note1");
synthTrack.addNote(note1);
Any ideas why the iterator won't work?
Change
noteIT < trackIT->getNoteList().end()
To
noteIT != trackIT->getNoteList().end()
Not all iterators support less than / greater than comparisons.
If you have c++11 you can use a range-based for loop:
for (Note& note : trackIT->getNoteList())
Or you can use BOOST_FOREACH
BOOST_FOREACH (Note& note, trackIT->getNoteList())
You haven't shown the definitions of getTrackList or getNoteList, but there's a common mistake people make - if you return a copy of the container instead of a reference to it, the iterators will be pointing to different containers making comparisons impossible. Not only that but since the containers are temporary any use of the iterators results in undefined behavior.
If you are really hardcoding the track key, then there will only ever be one track in the map because std::map stores unique keys...
long key = 1000009; //If yo are really doing this, this key is already inserted so it will fail to insert more.
Also, if you would like a more elegant approach you could use function object.
struct print_track
{
void operator()(const Track& track)
{
cout << track.getTrackName() << endl;
std::for_each(track.getNoteList().begin(), track.getNoteList().end(), print_track_name());
}
};
struct print_note_name
{
void operator()(const std::pair<long,Note>& note_pair)
{
cout << "---" << note_pair.second.getName() << endl;
}
};
//In use...
std::for_each(playlist.getTracklist().begin(), playlist.getTracklist.end(), print_track());