DataTable to JSon converter

Hi, i am working on some sort of JsonParcer that will save datatable in jsonfile and work in packed project .
For now i have this

and this is code of the SaveRowHandler function

void USpecialJsonParser::SaveRowHandler(FDataTableRowHandle ST,UStruct* USTR)
 {		
	 FString Row;
	 
	 //ST.GetRow<FDataTAableRowHandle>(Row);
	 GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, Row);
	 
	 FJsonObjectConverter::UStructToJsonObjectString(USTR,USTR,Row,0,0,0);


	 FString Path = FPaths::GameSourceDir() + FString("OutputData.json");				
	 std::string PathSTR = std::string(TCHAR_TO_UTF8(*Path));							
	
	 std::ofstream Out(PathSTR, std::ofstream::out);

	 std::string OutSTR = std::string(TCHAR_TO_UTF8(*Row));			
	 Out << OutSTR;
	 Out.close();
 }

It seems like problem in wrong usage of the function FJsonObjectConverter::UStructToJsonObjectString() but i dont realy understand it.

1 Like

The first parameter is the struct definition, the second parameter is an instance of that struct.

Assuming your data table is storing structs of type SRClientInfo, it should look like this :

FString Row;

// Get a pointer to the struct instance pointed by the row.
// The string parameter here is only used for providing context when logging errors/warnings. It's not useful otherwise.
// We use void* generic pointer because we don't know the type at compile time, since it is passed at runtime.
void* StructPtr = ST.GetRow<UScriptStruct>(TEXT("foobar"));

// Convert our struct instance to json, using the USTR struct schema.
FJsonObjectConverter::UStructToJsonObjectString(USTR, StructPtr, Row, 0, 0, 0);

UE_LOG(LogTemp, Warning, TEXT("%s"), *Row);
1 Like

First of all thank you Chatouille . But what should i enter in “foobar” place , is that a row name ?
And dont realy understand where the Json string exist after the execution of UStructToJsonObjectString() method.
i made this .

 `void  UParsing::HandleRowString(FDataTableRowHandle ST, UDataTable *DT,  UStruct* USTR)
 {
    FString Warnings; 	 	
    void* StructPtr  = ST.GetRow<UScriptStruct>(TEXT("art"));

	FJsonObjectConverter::UStructToJsonObjectString(USTR, StructPtr, Warnings, 0, 0, 0);

UE_LOG(LogTemp, Warning, TEXT("%s"),*Warnings);
 }`

and when i try to compile is failed

1 Like

You can literally put any string in place of “foobar”, as I mentioned in the comment it is just a debug tag for warning/error messages when the row fails to fetch. It is not the row name or anything relevant.

After the execution of UStructToJsonObjectString, the result json string exists in Warnings (in your case). That parameter is passed by reference, and filled by the function.

Regarding the error, whoops it looks like I miscalculated the expected type. Unfortunately we’re hitting a little limitation here due to forced templates, so we can’t use FindRow. But here is a workaround that should do the trick :

FString JsonResult;

// Get a pointer to the struct instance pointed by the row.
uint8* const* RowDataPtr = ST.DataTable->GetRowMap().Find(ST.RowName);
if (RowDataPtr)
{
	void* StructPtr = (void*)*RowDataPtr;

    // Convert our struct instance to json, using the USTR struct schema.
	FJsonObjectConverter::UStructToJsonObjectString(USTR, StructPtr, JsonResult, 0, 0, 0);

	UE_LOG(LogTemp, Warning, TEXT("JSON Result: %s"), *JsonResult);
}
else
{
	UE_LOG(LogTemp, Warning, TEXT("Row not found"));
}
1 Like

Ok now i have something but, in output json string something wrong, maybe you know why converter perform like that ?

That’s weird for sure. Any chance you were testing after a hot-reload ? If so, try to recompile without editor open and then relaunch.

No didn’t worked out , i recompile with closed editor and even create a new project but that didn’t realy change situation(. Iam stuck

Looks like you are out of luck with those data tables…

I don’t know what is causing this, but here is a workaround that modifies the JsonObject to take out those ugly identifiers, before converting to string.

void FixJsonFieldNames(TSharedPtr<FJsonValue> Elem)
{
	if (Elem && Elem->Type == EJson::Object && Elem->AsObject())
	{
		TArray<FString> Keys;
		Elem->AsObject()->Values.GenerateKeyArray(Keys);
		for (auto& Key : Keys)
		{
			auto Value = Elem->AsObject()->GetField<EJson::None>(Key);
			FixJsonFieldNames(Value);
			if (Key.Len() > 35 && Key[Key.Len() - 33] == TEXT('_'))
			{
				FString NewKey = Key.LeftChop(33);
				int32 i;
				if (NewKey.FindLastChar(TEXT('_'), i))
				{
					NewKey = NewKey.Left(i);
					Elem->AsObject()->SetField(NewKey, Value);
					Elem->AsObject()->RemoveField(Key);
				}
			}
		}
	}
	else if (Elem && Elem->Type == EJson::Array)
	{
		for (auto& Value : Elem->AsArray())
		{
			FixJsonFieldNames(Value);
		}
	}
}

Now you need to generate the object first before converting to string :

// Convert to json object
auto JsonObject = MakeShared<FJsonObject>();
FJsonObjectConverter::UStructToJsonObject(USTR, StructPtr, JsonObject, 0, 0, 0);

// Fix field names
FixJsonFieldNames(MakeShared<FJsonValueObject>(JsonObject));

// Convert to json string
FString JsonString;
auto JsonWriter = TJsonWriterFactory<TCHAR, TPrettyJsonPrintPolicy<TCHAR>>::Create(&JsonString, 0);
if (FJsonSerializer::Serialize(JsonObject, JsonWriter))
{
	UE_LOG(LogTemp, Warning, TEXT("%s"), *JsonString);
}
JsonWriter->Close();