Parse JSON File with Array of Objects without converting to USTRUCT

Hello,

I have multiple JSON files as follows. I am trying to create an all-purpose plugin to handle some JSON object-array files given to me.

// Multiple files like this:
[
    {
        // JSON Object
    },
    {
        // JSON Object
    }
]

I have seen discussion threads such as Parsing json array of objects suggesting using FJsonObjectConverter::JsonArrayStringToUStruct after reading the file as a FString to convert the JSON Array to a TArray<USTURCT of JSON Object A>. I tried defining USTRUCTs for the JSON objects to perform the conversion using this function. However, I have hit some hurdles:

  1. The JSON Objects per-file are somewhat different, requiring custom structs per-file. However, the JSON Objects have a lot of attributes, and therefore the USTRUCTs are getting massive (500+ lines defining structs per file).
  2. I only need certain attributes from the JSON Objects that match a certain pattern (like having a “b” at the start). Unfortunately, there quite a few of these and I cannot get a definite list of attributes needed, since I am trying to create an all-purpose plugin.

Given these issues, I believe that it would be easier just to directly handle the JSON files as JSON Objects rather than converting to USTRUCT and just parse all keys for what I want to match to. However, it seems that FJsonSerializer::Deserialize() cannot handle JSON object-array files.

TSharedPtr<FJsonObject> JsonParsed = MakeShareable(new FJsonObject());
const TSharedRef<TJsonReader<>> JsonReader = TJsonReaderFactory<>::Create(json);
if (FJsonSerializer::Deserialize(JsonReader, JsonParsed) && JsonParsed.IsValid())
{
	// Doesn't run
	UE_LOG(LogScript, Warning, TEXT("PRINTING TYPE: %s"), *JsonParsed->GetStringField("Type"));
}
else
{
	// This prints
	UE_LOG(LogScript, Warning, TEXT("CANNOT CONVERT!"));
}

Is there any UE function that handles JSON object arrays while preserving the JSON object for easy field matching?

Ummm, I’m not 100% sure what you’re asking, but there is a DOM-style JSON interface here:

Is that what you want?

The DOM objects/functions you linked are what the FJsonSerializer and FJsonConvertor my code above use as input/output. The issue is that although I can convert a JSON object string to one of the DOM objects (like FJsonObject) I cannot convert a JSON object array to something like a TArray<FJsonObject>.

It seems that FJsonSerializer cannot handle JSON array strings ([{}, {}, …]) and only handles single JSON object (just {}). It is possible to convert a JSON array string to a TArray of USTRUCTs instead of FJsonObjects, but that requires me to create gigantic structs and cannot handle getting all fields that match a pattern which I require.

Normally I would expect a JSON parser to parse [{},{},{}] as an FJsonValueArray, the elements of which are FJsonObjects. Is that not what the unreal parser does?

Sorry for the late response. I tested using FJsonValueArray (well, TArray<TSharedPtr<FJsonValue>> which I believe is the same thing) and it worked! Thank you for your help!

I guess I never tried using the parser to parse into an array explicitly - dumb mistake. Thank you again!

For anyone stumbling on this thread, here is the code I used which worked:

FString json = "[{\"Type\": \"TestType\",\"Name\": \"TestName\",\"Drop\": \"TestDrop\",\"OptionalStr\": \"TestOptional\"}]";
TArray<TSharedPtr<FJsonValue>> JsonParsed;
const TSharedRef<TJsonReader<>> JsonReader = TJsonReaderFactory<>::Create(json);
if (FJsonSerializer::Deserialize(JsonReader, JsonParsed) && JsonParsed[0].IsValid())
{
	// Prints TestType
	UE_LOG(LogScript, Warning, TEXT("PRINTING TYPE: %s"), *JsonParsed[0].Get()->AsObject()->GetStringField("Type"));
}
else
{
	// Doesn't print, it works!
	UE_LOG(LogScript, Warning, TEXT("CANNOT CONVERT!"));
}
1 Like