Panmigo
(Panmigo)
February 17, 2021, 12:22am
1
I have a nested json with the following structure within UE4:
{
"boundary_points__per__cell": {
"0":
{
"x": 16.451330042628662,
"y": 2.0813326861577965
},
{
"x": 16.755262971791506,
"y": 2.0406535171257136
}
],
"1":
{
"x": -1.6378002918100634,
"y": 4.9689057223409412
},
{
"x": 0.9452331911724825,
"y": 6.1469903490163311
}
]
}
}
I tried using proposed techniques from other threads that suggest using the JsonObjectStringToUStruct. In particular I have the following structs to parse the json logic:
USTRUCT()
struct FBoundaryPoint
{
GENERATED_USTRUCT_BODY()
UPROPERTY()
int32 x;
UPROPERTY()
int32 y;
};
USTRUCT()
struct FBoundaryPoints
{
GENERATED_USTRUCT_BODY()
UPROPERTY()
TArray<FBoundaryPoint> BoundaryPoints;
};
USTRUCT()
struct FVoronoiStruct
{
GENERATED_USTRUCT_BODY()
UPROPERTY()
TMap<FString, FBoundaryPoints> boundary_points__per__cell;
};
However, Iam unable to find a solution since, the parsed objects return only the keys of the dictionary (“0”. “1”) without parsing correctly the array of elements.
Kris
(Kris)
February 19, 2021, 3:06am
2
Manually doing it not an option?
TSharedPtr<FJsonObject> FileAsJson;
TArray<TSharedPtr<FJsonValue> > Points = FileAsJson->GetArrayField(TEXT("boundary_points__per__cell")));
for(int32 i = 0; i < Points.Num() ++i)
{
TSharedPtr<FJsonObject>& PointsObject = Points*->AsObject();
FVector2D Coords;
if (PointsObject->HasTypedField<EJson::Number>(TEXT("x")))
{
Coords.X = PointsObject->TryGetNumberField(TEXT("x"));
}
if (PointsObject->HasTypedField<EJson::Number>(TEXT("y")))
{
Coords.Y = PointsObject->TryGetNumberField(TEXT("y"));
}
etc etc
}
Panmigo
(Panmigo)
March 23, 2021, 3:02pm
3
Yes unfortunately I had to switch to a manual parsing and everything worked as expected. Thanks
If anyone is struggling with nested Jsons and stumbles on this thread, I’ll point out that the above solution is not 100% correct because “boundary_points__per__cell ” is not referring to an array. It is referring to another dict.
So using the following will give you an error!
TArray<TSharedPtr > Points = FileAsJson->GetArrayField(TEXT(“boundary_points__per__cell”)));
What helped me here was using the Values member variable in the FJsonObject class.
You can use this to directly get a TMap with the keys “0”, “1”, “2”, etc in this example.
I struggled with this so hope it saves you some trouble!
TMap<FString, FString> URequestManagerBase::DeSerializeJsonContent(const FString& JsonContent)
{
TMap<FString, FString> ReturnMap;
TSharedPtr<FJsonObject> JsonObject;
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonContent);
if (FJsonSerializer::Deserialize(Reader, JsonObject) && JsonObject.IsValid())
{
for (const TPair<FString, TSharedPtr<FJsonValue>>& Pair : JsonObject->Values)
{
CheckJsonType(Pair, &ReturnMap);
}
}
return ReturnMap;
}
void URequestManagerBase::CheckJsonType(TPair<FString, TSharedPtr<FJsonValue>> Json, TMap<FString, FString>* Map)
{
if (Json.Value->Type == EJson::Object || Json.Value->Type == EJson::Array)
{
if (Json.Value->Type == EJson::Object)
{
for (const TPair<FString, TSharedPtr<FJsonValue>>& Pair : Json.Value->AsObject()->Values)
{
CheckJsonType(Pair, Map);
}
}
else if (Json.Value->Type == EJson::Array)
{
int32 Index = 1;
for (const auto& ArrayValue : Json.Value->AsArray())
{
Map->Add(Json.Key + "_" + FString::FromInt(Index), ArrayValue->AsString());
Index++;
}
}
}
else
{
Map->Add(Json.Key, Json.Value->AsString());
}
}