I'm writing an article about a JSON reader I'm building, and I have these extractor structures that allow you to define paths to JSON values you want to pick out of the document. The reader can take these extractors and use them to populate your specified variables values from the document.
The extractors nest, meaning each one can potentially have children, which they take in the constructor. Because they take children in the constructor, you have to create the children first, and work from the leaves to the root.
A
JsonElement
is basically a variant type that can hold any kind of JSON value
A
JsonExtractor
structure represents one set of path segments or a value query. You can use one to
1. Navigate to one or more fields on an object
or
2. Navigate to one or more array elements in an array
or
3. extract the
JsonElement
value at the current position (could be string, boolean, number or null or undefined or array or object)
Whether it's type 1, 2 or 3 is determined by which constructor overload you called - did you give it a field list (#1), and indices list (#2), or a JsonElement pointer (#3)?
A query engine over this to abstract it would make it easier but I'm trying to avoid writing a query engine on top of it because this runs even on 8-bit with <8kB of ram and I want to keep it that way.
This creates an extractor that combs a JSON document for various elements, namely:
$.id
$.name
$.number_of_episodes
$.last_episode_to_air.name
$.created_by[0].name
$.created_by[0].profile_path
JsonElement creditName;
JsonElement creditProfilePath;
JsonElement id;
JsonElement name;
JsonElement numberOfEpisodes;
JsonElement lastEpisodeToAirName;
const char* createdByFields[] = {"name","profile_path"};
JsonExtractor createdByExtractions[] = {
JsonExtractor(&creditName),
JsonExtractor(&creditProfilePath)
};
JsonExtractor createdByExtraction(createdByFields,2,createdByExtractions);
JsonExtractor createdByArrayExtractions[] = {
createdByExtraction
};
size_t createdByArrayIndices[] = {0};
JsonExtractor createdByArrayExtraction(
createdByArrayIndices,
1,
createdByArrayExtractions
);
const char* lastEpisodeFields[] = {"name"};
JsonExtractor lastEpisodeExtractions[] = {
JsonExtractor(&lastEpisodeToAirName)
};
JsonExtractor lastEpisodeExtraction(
lastEpisodeFields,
1,
lastEpisodeExtractions
);
const char* showFields[] = {
"id",
"name",
"created_by",
"number_of_episodes",
"last_episode_to_air"
};
JsonExtractor showExtractions[] = {
JsonExtractor(&id),
JsonExtractor(&name),
createdByArrayExtraction,
JsonExtractor(&numberOfEpisodes),
lastEpisodeExtraction
};
JsonExtractor showExtraction(showFields,5,showExtractions);
I don't like doing nested structures in C and C++ generally because it creates code like this, but sometimes it feels like the best way given the situation.
my question is, given I'm writing an article that explains it, how ugly is this really? Is this code something a decent developer can understand if they study it a bit or do you think I only understand it because I wrote it?
Do you have any ideas to restructure it maybe if it can be done without adding a ton of extra code/abstractions (this is a close-to-the-metal API and library)
What I have tried:
I've tried the code in the above. This section doesn't really apply to me question, sorry.