Hi all,
I'm struggling to parse a JSON file that has nested objects. Below is a short example of the type of input file that I'm trying to parse:
{
"parameterA" : "valueA",
"parameterB" : [{"status": true, "B_1": 2.116, "B_2": 3}],
"parameterC" : 1.23456
}
At the moment, to parse a simple file, I read the whole input into a string and parse it using the Parse() function in the Document class.
I can access the top level parameters as document["parameterA"] or using the FindMember() function without any problems, but I haven't found a simple way to parse and access the parameters in the nested object in parameterB.
I've found these two threads that discuss this topic:
Â
I can't really seem to decipher what I need to do. I was presuming that the Parse() function would parse the input so that I could access parameters as document["parameterB"]["status"], but that doesn't seem to be the case.
Does anyone have a succinct way of parsing and accessing data in nested objects?
Thanks in advance!
By using Document::Parse(), the whole JSON is fully parsed and stored it into Document.
Since parameterB's value is an array (note the [...]), querying status require accessing the first element of it, e.g.
assert(document["parameterB"][0]["status"].GetBool() == true);
For this JSON, I think it may have multiple elements in parameterB, otherwise it don't need to be an array. If this is the case, you can traverse the array:
Value& parameterB = document["parameterB"];
assert(parameterB.IsArray());
for (SizeType i = 0; i < parameterB.Size(); i++) {
// work with parameterB[i]["status"], parameterB[i]["B_1"], etc.
}
Another syntax is to use iterator:
for (Value::ConstValueIterator itr = parameterB.Begin(); itr = parameterB.End(); ++itr) {
// work with (*itr)["status"], etc.
}
Great, thanks!
One last question, the way that I ascertain that parameterB exists at the moment is that I have a find() function that wraps FindMember():
//! Find parameter.
ConfigIterator find( const rapidjson::Document& config, const std::string& parameterName )
{
const ConfigIterator iterator = config.FindMember( parameterName.c_str( ) );
if ( iterator == config.MemberEnd( ) )
{
std::ostringstream error;
error << "ERROR: \"" << parameterName << "\" missing from config file!";
throw std::runtime_error( error.str( ) );
}
return iterator;
}
If the key is found, the function returns an iterator to it and otherwise it throws an exception.
In this case, after running find( document, "parameterB"), I'd like to then run something like find( parameterBIterator, "status").
Is there a way that I can set up my code to use the same/similar find() function for status?
You can do something like find(parameterBIterator->value, "status"). But be aware that parameterB is an array, not an object.
Besides, you may be interested in our newly developed feature: JSON Pointer. http://miloyip.github.io/rapidjson/md_doc_pointer.html
Ah yes, very cool. I just realised that for my current input file parameterB doesn't have to be an array indeed. So I've just set the value to the object directly. I'll try to figure out if I can use the JSON Pointer feature instead. I just need to figure out how to throw an appropriate exception if the key can't be found in the document.
Thanks for all your help!
What if you do not know what is in the JSON. Example below contains a nested JSON (from a file):
{
"parameter1": {
"parameter2": {
"parameterA": "valueA",
"parameterB": "valueB",
"parameterC": "valueC"
}
}
}
How do I retrieve each member independently whether I know it is nested or not? The example above assumes you know "parameterB" as you have used "assert" to
Value& parameterB = document["parameterB"];
assert(parameterB.IsArray());
But with my example code when you use the "ConstValueIterator" to loop through you will only get the first object, then it will stop as you hit another object. Am I correct in stating that? Or am I missing something?
You can use Begin() and End() for iterating arrays.
Similarly, use MemberBegin() andMemberEnd()` for iterating objects.
You can refer to the Tutorial.
I have used the tutorial and the code in there as well:
static const char* kTypeNames[] = { "Null", "False", "True", "Object",
"Array", "String", "Number" };
for (Value::ConstMemberIterator itr = document.MemberBegin(); itr !=
document.MemberEnd(); ++itr)
{
printf("Type of member %s is %s\n",itr->name.GetString(),
kTypeNames[itr->value.GetType()]);
I have a file that contains nested objects. The problem is that it prints
out the first object but nothing else (I thought it would print out
everything cause even the nested objects are part of the first object).
I have also used the "reader" and the "handler" to print our the key-string
pairs. What I am trying to do is convert JSON to XML, but my c++ skills
are lacking. I was trying to Parse the JSON to a DOM, then have access to
the items to convert to XML. I have also thought about a custom handler.
On Thu, Nov 12, 2015 at 9:42 PM, Milo Yip [email protected] wrote:
You can use Begin() and End() for iterating arrays.
Similarly, use MemberBegin() andMemberEnd()` for iterating objects.
You can refer to the Tutorial
http://rapidjson.org/md_doc_tutorial.html#QueryObject.—
Reply to this email directly or view it on GitHub
https://github.com/miloyip/rapidjson/issues/336#issuecomment-156305353.
@miloyip I am trying to parse a JSON value within multiple nested array, i.e. the string value of "description" within "textAnnotations" in "responses" array.
{
"responses": [
{
"textAnnotations": [
{
"locale": "bn",
"description": "টিকা\n",
"boundingPoly": {
"vertices": [
{
.................
..................
}
}
]
}
I am trying Pointers but no success. Looking for suggestions in this regard.
const std::string& tmp = response.str();
const char* json_response = tmp.c_str();
Document parsed;
parsed.Parse(json_response);
if (Value* LPdt = GetValueByPointer(parsed, "/responses/textAnnotations/"))
{
std::cout << (*LPdt)["description"].GetString();
// ...
}
else {
//
std::cout << "--------<<<<<<<<<<<<<< Unable to resolve the value of the pointer. Handle error.---------------------" << std::endl;
}
Most helpful comment
By using
Document::Parse(), the whole JSON is fully parsed and stored it intoDocument.Since
parameterB's value is an array (note the[...]), queryingstatusrequire accessing the first element of it, e.g.For this JSON, I think it may have multiple elements in
parameterB, otherwise it don't need to be an array. If this is the case, you can traverse the array:Another syntax is to use iterator: