8

I would like to iterate over each of entries in a json object, but I am getting one incomprehensible error after the other. How to correct the following example?

#include <iostream>

#include <nlohmann/json.hpp>

using json = nlohmann::json;

void bla(std::string a) {
    std::cout << a << '\n'; 
}

int main() {
    json RecentFiles;

    RecentFiles["1"]["Name"] = "test1.txt";
    RecentFiles["1"]["Last modified"] = "monday";
    RecentFiles["1"]["Score"] = 5.0f;

    RecentFiles["2"]["Name"] = "test2.txt";
    RecentFiles["2"]["Last modified"] = "tuesday";
    RecentFiles["2"]["Score"] = 5.0f;


    for (auto it = RecentFiles.begin(); it != RecentFiles.end(); ++it) {
           bla("JSON: Recent file = " + it.value()["Name"]);    
    }

    std::cout << RecentFiles; }

Error:

prog.cc: In function 'int main()':
prog.cc:18:31: error: invalid conversion from 'const char*' to 'nlohmann::detail::iter_impl<nlohmann::basic_json<> >::difference_type {aka long int}' [-fpermissive]
         std::cout << it["Name"];
                               ^
In file included from prog.cc:2:0:
./nlohmann/json.hpp:4418:15: note: initializing argument 1 of 'nlohmann::detail::iter_impl<BasicJsonType>::reference nlohmann::detail::iter_impl<BasicJsonType>::operator[](nlohmann::detail::iter_impl<BasicJsonType>::difference_type) const [with BasicJsonType = nlohmann::basic_json<>; nlohmann::detail::iter_impl<BasicJsonType>::reference = nlohmann::basic_json<>&; nlohmann::detail::iter_impl<BasicJsonType>::difference_type = long int]'
     reference operator[](difference_type n) const
               ^

The above is done in the sandbox

https://wandbox.org/permlink/LNck7Gktm14bmPy0

This is not actual code that I am using, I just want to see if I can understand how to do the various basic things that I need to do with JSON.

Currently I understand so little, that I do not know if what I am doing is essentially correct but just breaks due to something stupid, or if I am doing something fundamentally wrong.

mnr
  • 604
  • 2
  • 7
  • 15
  • 2
    What's the error you're getting? – Stephen Newell Mar 30 '19 at 12:47
  • I also tried adding .string() . Since I am going to do complicated stuff with it that are defined in other functions for std::string objects, I would like to get the entry in the data as an std::string (not some other kind of string like string_t). I just need a simple loop that goes over all the entries, and allows me to get what is inside in a standard class – mnr Mar 30 '19 at 12:53
  • did you tried to use stringstream or atoi() function in cstdlib for convert "test1.txt" to unsigned int ? maybe you should just convert it , or there's a problem on the JSON header file. – Skiller Dz Mar 30 '19 at 14:02
  • I found that if I use bla(it.value()["Name"].dump()); then I get the string that I want to get, but enclosed with " ". I am now just going to make a simple function that removes those " again so that I can continue, but it feels a bit like this is a hack and not the correct and realiable way to do it – mnr Mar 30 '19 at 16:04
  • By the way, it is wandbox instead of sandbox, although the latter quite fits the context ;-D – L. F. Apr 22 '19 at 10:59

1 Answers1

18

The nlohmann json library promotes itself as "JSON for modern C++" and aspires to behave "just like an STL container". There is, however, no container in the C++ standard library that is both "vector-like" and "map-like", and that supports both begin/end iterators over values, and begin/end iterators over key/value pairs. So something new is needed.

nlohmann's original solution was to copy jsoncpp's approach, which supports begin/end iterators for json arrays, and adds a distinctly unstandard key() function to the iterator to also support json objects. So you could write

for (auto it = RecentFiles.begin(); it != RecentFiles.end(); ++it)
{
    std::cout << it.key() << "\n";
    std::cout << (*it)["Name"].get<std::string>() << "\n";
    std::cout << (*it)["Last modified"].get<std::string>() << "\n";
}

But being an unstandard way of iterating over key/values, this doesn't have standard library support for range based for loops over key/values.

nlohmann later added the json::items() function that does support iteration over json objects with standard iterators, and which does have standard library support for range based for loops, viz.

int main()
{
    json RecentFiles;

    RecentFiles["1"]["Name"] = "test1.txt";
    RecentFiles["1"]["Last modified"] = "monday";
    RecentFiles["1"]["Score"] = 5.0f;

    RecentFiles["2"]["Name"] = "test2.txt";
    RecentFiles["2"]["Last modified"] = "tuesday";
    RecentFiles["2"]["Score"] = 5.0f;

    for (const auto& item : RecentFiles.items())
    {
        std::cout << item.key() << "\n";
        for (const auto& val : item.value().items())
        {
            std::cout << "  " << val.key() << ": " << val.value() << "\n";
        }
    }
    std::cout << "\nor\n\n";
    for (const auto& item : RecentFiles.items())
    {
        std::cout << item.key() << "\n";
        std::cout << "  " << item.value()["Name"].get<std::string>() << "\n";
        std::cout << "  " << item.value()["Last modified"].get<std::string>() << "\n";
        std::cout << "  " << item.value()["Score"].get<double>() << "\n";
    }
}

Output:

1
  Last modified: "monday"
  Name: "test1.txt"
  Score: 5.0
2
  Last modified: "tuesday"
  Name: "test2.txt"
  Score: 5.0

or

1
  test1.txt
  monday
  5
2
  test2.txt
  tuesday
  5
Daniel
  • 728
  • 7
  • 11