Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Printing attribute names #39

Closed
luxe opened this issue Mar 1, 2015 · 7 comments
Closed

Printing attribute names #39

luxe opened this issue Mar 1, 2015 · 7 comments

Comments

@luxe
Copy link
Contributor

luxe commented Mar 1, 2015

What would be the best way to iterate over a json object and print the attribute names?
My goal would be to have something like this:

example json:

{
"example": {
    "a": "hello",
    "b": "world",
    "c": "text"
  }
}

example printing code:

auto j = nlohmann::json::parse(Read_Entire_File_Into_String("example.json"));
auto element = j["example"];
for (auto const& it: element) {
    std::cout << it.attribute_name() << std::endl;
}
// I made up 'Read_Entire_File_Into_String', but it does what you'd expect.
// the attribute_name() method doesn't exist, but I wish that it had.

example results:

a
b
c

Not everything has an attribute name, in which case, it could return an empty string, throw an exception, or return std::optional.

I thought this might be easy to implement, but it appears that all of the attribute names are stored in the parent object, which means that when we iterate over an object, each iterator points to an object that has no way of finding out its own attribute name.

for example, if I were to edit json.hpp and give the basic_json class this public member function:

    inline string_t attribute_name() const noexcept
    {
        std::string str;
        if (m_type == value_t::object){
            for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i){
                str += escape_string(i->first) + " ";
            }
        }

        return str;
    }

and run client code like this:

#include "json.hpp"
#include <iostream>

void Recursive_Print(nlohmann::json const& element, unsigned int depth);

int main(){
  auto element = nlohmann::json::parse(Read_Entire_File_Into_String("changelog.json"));

  if (element.is_null()){ std::cout << "null " << element.attribute_name() << std::endl;}
  if (element.is_boolean()){std::cout << "bool " << element.attribute_name() << std::endl;}
  if (element.is_number()){std::cout << "number " << element.attribute_name() << std::endl;}
  if (element.is_object()){std::cout << "object " << element.attribute_name() << std::endl;}
  if (element.is_array()){std::cout << "array " << element.attribute_name() << std::endl;}
  if (element.is_string()){std::cout << "string " << element.attribute_name() << std::endl;}
}
void Recursive_Print(nlohmann::json const& element, unsigned int depth){
  for (auto const& it: element) {
    Print_Character_N_Times('-',depth); 
    if (it.is_null()){ std::cout << "null " << it.attribute_name() << std::endl;}
    if (it.is_boolean()){std::cout << "bool " << it.attribute_name() << std::endl;}
    if (it.is_number()){std::cout << "number " << it.attribute_name() << std::endl;}
    if (it.is_object()){std::cout << "object " << it.attribute_name() << std::endl; Recursive_Print(it,++depth);}
    if (it.is_array()){std::cout << "array " << it.attribute_name() << std::endl; Recursive_Print(it,++depth);}
    if (it.is_string()){std::cout << "string " << it.attribute_name() << std::endl;}
  }
}
//PRETTY MESSY.  BUT YOU GET THE GIST

it would result in the following:

object example 
-object a b c 
--string 
--string 
--string

I think that illustrates my point about attribute names being stored in the parents.

Anyway, do you have any thoughts on how I could accomplish this?

@Iced-Sun
Copy link

Iced-Sun commented Mar 4, 2015

Yes I found this is very annoying because it FORCES the user know all the possible attributes.

I think it would be convenient to just follow the convention of std::map, i.e., returning a (key, value) pair instead of the value only, when enumerating the json object.

@nlohmann
Copy link
Owner

nlohmann commented Mar 6, 2015

Dear @luxe,

thanks for reporting! I shall have a look once I'm back from holidays.

All the best
Niels

@amirmasoudabdol
Copy link
Contributor

That would be really useful. Even if you know the keys beforehand, being able to iterate over them will save a lot of lines.

@nlohmann
Copy link
Owner

This is related to #46 and #49. I have an idea how to solve it. Stay tuned...

@nlohmann nlohmann self-assigned this Mar 24, 2015
@luxe
Copy link
Contributor Author

luxe commented Mar 24, 2015

Yay!

@nlohmann
Copy link
Owner

All iterators have now member functions key() to retrieve the key for objects and value() to retrieve the value. This should fix the mentioned issue.

@amirmasoudabdol
Copy link
Contributor

That's great. Thanks!

GerHobbelt pushed a commit to GerHobbelt/nlohmann-json that referenced this issue May 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants