Tencent / rapidjson

A fast JSON parser/generator for C++ with both SAX/DOM style API
http://rapidjson.org/
Other
14.17k stars 3.53k forks source link

Parse an array of objects in C++ using rapidjson. #1235

Open srikarad07 opened 6 years ago

srikarad07 commented 6 years ago

I'm trying to parse the following JSON file in c++. I would like to iterate over the 'attributes' array and obtain the value of the string:'value' for a specific value of a string:'name' of that attribute object. For ex: I would like to parse this JSON file and obtain the 'value' for 'mass'.

{
"active": true,
"apiTier": 0,
"attributes": [
    {
        "description": "Given in the datasheet as '0.33 kg (0.73 lbm)'.",
        "maximumValue": "",
        "measurementUnit": "kg",
        "minimumValue": "",
        "name": "mass",
        "productConfiguration": "base",
        "value": "0.33"
    },    
    {
        "description": "",
         "maximumValue": "",
        "measurementUnit": "",
        "minimumValue": "",
        "name": "propellant-type",
        "productConfiguration": "base",
        "value": "hydrazine"
    },
    {
        "description": "Given in the datasheet as 'Thrust/Steady State' and the specified value is also reported as '(0.05-0.230) lbf'.",
        "maximumValue": "1.02",
        "measurementUnit": "N",
        "minimumValue": "0.22",
        "name": "thrust",
        "productConfiguration": "base",
        "value": ""
    }
]

I am trying to do this in C++ using rapidjson library to parse the JSON file. Below is my implementation for the parsing of the JSON file. What I would like to do is within the for loop, for a specific 'value' for a string 'name' (for ex: mass) obtain the other 'values' for string such as 'maximumValue', 'minimumValue', 'value' etc.

#include <fstream>
#include <sstream>
#include <string>
#include <rapidjson/document.h>

int main()
{
   std::ifstream inputFile( "/path/to/json/file/" );
   std::stringstream jsonDocumentBuffer;
   std::string inputLine;

   while ( std::getline( inputFile, inputLine ) )
   {
      jsonDocumentBuffer << inputLine << "\n";
   }
   rapidjson::Document config;
   config.Parse( jsonDocumentBuffer.str( ).c_str( ) );

   rapidjson::Value::MemberIterator attributeIterator = config.FindMember( "attributes" );
   int counter = 0; 
   const rapidjson::Value& attributes = config[ "attributes" ];
   for ( rapidjson::Value::ConstMemberIterator iterator = attributes.MemberBegin(); iterator != attributes.MemberEnd(); ++iterator )
   {
      std::cout << ++counter << std::endl;
   }
}
miloyip commented 6 years ago

Since attributes is an array (you may check it with attributes.IsArray(), so you should iterates the array first:

assert(attributes.IsArray()); // attributes is an array
for (rapidjson::Value::ConstValueIterator itr = attributes.Begin(); itr != attributes.End(); ++itr) {
    const rapidjson::Value& attribute = *itr;
    assert(attribute.IsObject()); // each attribute is an object
    for (rapidjson::Value::ConstMemberIterator itr2 = attribute.MemberBegin(); itr2 != attribute.MemberEnd(); ++itr2) {
        std::cout << itr2->name.GetString() << " : " << itr2->value.GetString() << std::endl;
    }
}
srikarad07 commented 6 years ago

Thanks for your answer!

My question was to obtain the value of string such as ('value', 'maximumValue', etc..) for a specific value (Eg: mass) for the string 'name'. However, the above code iterates over all the strings and extract their specific values.

A small edit: In the above code I get an error for using 'rapidjson::Value:: ConstIterator'. I looked around on the rapidjson tutorials and noticed it is 'rapidjson::Value::ConstValueIterator'.

miloyip commented 6 years ago

So you need to firstly find which attribute is "mass", and then obtain the properties. I fixed the above example.

srikarad07 commented 6 years ago

Yup, exactly that's what I need to do.

maxwangsongyuan commented 5 years ago

I don't think the above example is fixed as I cannot see where did you obtain the "mass" property. Can you please add it again. Thank you!

BruceYang-yeu commented 3 years ago

assert(attributes.IsArray()); // attributes is an array for (rapidjson::Value::ConstValueIterator itr = attributes.Begin(); itr != attributes.End(); ++itr) { const rapidjson::Value& attribute = *itr; assert(attribute.IsObject()); // each attribute is an object for (rapidjson::Value::ConstMemberIterator itr2 = attribute.MemberBegin(); itr2 != attribute.MemberEnd(); ++itr2) { std::cout << itr2->name.GetString() << " : " << itr2->value.GetString() << std::endl; } }

Since attributes is an array (you may check it with attributes.IsArray(), so you should iterates the array first:

assert(attributes.IsArray()); // attributes is an array
for (rapidjson::Value::ConstValueIterator itr = attributes.Begin(); itr != attributes.End(); ++itr) {
    const rapidjson::Value& attribute = *itr;
    assert(attribute.IsObject()); // each attribute is an object
    for (rapidjson::Value::ConstMemberIterator itr2 = attribute.MemberBegin(); itr2 != attribute.MemberEnd(); ++itr2) {
        std::cout << itr2->name.GetString() << " : " << itr2->value.GetString() << std::endl;
    }
}

add judge value is string, avoid crash when value is not string type if (itr2->value.IsString()) std::cout << itr2->name.GetString() << " : " << itr2->value.GetString() << std::endl;