I have a web service, which offers labelled 3d points which were serialized using Pandas' DataFrame's to_json method like so:
{
"x": {
"6579": 0.2108709365,
"1079": -0.7737237811
},
"y": {
"6579": -0.9016159773,
"1079": -1.2094773054
},
"z": {
"6579": -0.164285481,
"1079": -1.3477079868
},
"label": {
"6579": 4,
"1079": 6
}
}
I have an AHttpActor
class, which can request and print the data to the screen:
#pragma once
#include "GameFramework/Actor.h"
#include "Runtime/Online/HTTP/Public/Http.h"
#include "CoreMinimal.h"
#include "HttpActor.generated.h"
UCLASS()
class UE4CPPEXAMPLE_API AHttpActor : public AActor
{
GENERATED_BODY()
public:
AHttpActor(const class FObjectInitializer& ObjectInitializer);
virtual void BeginPlay() override;
FHttpModule* Http;
void OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
};
#include "UE4CPPExample.h"
#include "HttpActor.h"
#include "Templates/SharedPointer.h"
AHttpActor::AHttpActor(
const class FObjectInitializer& ObjectInitializer
)
: Super(ObjectInitializer)
{
Http = &FHttpModule::Get();
}
void AHttpActor::BeginPlay()
{
Super::BeginPlay();
TSharedRef < IHttpRequest, ESPMode::ThreadSafe > Request = Http->CreateRequest();
Request -> OnProcessRequestComplete().BindUObject(
this,
&AHttpActor::OnResponseReceived
);
Request -> SetURL("http://localhost:2144/sample?limit=1");
Request -> SetVerb("GET");
Request -> ProcessRequest();
}
void AHttpActor::OnResponseReceived(
FHttpRequestPtr Request,
FHttpResponsePtr Response,
bool bWasSuccessful
){
GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, Response -> GetContentAsString());
}
I am a newcomer to C and most of the examples are assuming a list of common objects in the data. So, I am having a surprisingly hard time with this:
How do I parse this JSON string to a C object and iterate over it, one point (x, y, z, label) at a time?
To make my request more clear, I want to do the following in C instead of Python:
import json
from urllib.request import urlopen
with urlopen('http://localhost:2144/sample?limit=2') as response:
data_dictionary = json.loads(response.read())
for key in data_dictionary['x'].keys():
x = data_dictionary['x'][key]
y = data_dictionary['y'][key]
z = data_dictionary['z'][key]
label = data_dictionary['label'][key]
print((x, y, z, label))
CodePudding user response:
I've never done Unreal C development before, but something like this should work:
#include <string>
void AHttpActor::OnResponseReceived(
FHttpRequestPtr Request,
FHttpResponsePtr Response,
bool bWasSuccessful
){
FString fcontent = Response->GetContentAsString();
std::string content = TCHAR_TO_UTF8(*fcontent);
nlohmann::json j = nlohmann::json::parse(content);
for (const auto &[key, _] : j["x"].items())
{
std::string x = j["x"][key];
std::string y = j["y"][key];
std::string z = j["z"][key];
std::string label = j["label"][key];
// do your stuff
}
}
CodePudding user response:
I would rather export this pandas dataframe to CSV.
content = df.to_csv( index=False, sep=' ')
Then from C do something like:
FString fcontent = Response->GetContentAsString();
std::string content = TCHAR_TO_UTF8(*fcontent);
std::istringstream ifs( content );
while ( ifs.good() ) {
double x, y, z;
std::string label;
ifs >> x >> y >> z >> label;
... (do something with x y z label) ...
}
Then you don't need to mess around importing and building external libraries, managing versions etc which can be a hassle sometimes.
CodePudding user response:
I tried parsing the string using JsonObjectStringToUStruct. Here is the header:
USTRUCT()
struct FLabels
{
GENERATED_USTRUCT_BODY()
FLabels() {}
UPROPERTY()
TMap<FString, FString> label;
};
USTRUCT()
struct FXs
{
GENERATED_USTRUCT_BODY()
FXs() {}
UPROPERTY()
TMap<FString, float> x;
};
USTRUCT()
struct FYs
{
GENERATED_USTRUCT_BODY()
FYs() {}
UPROPERTY()
TMap<FString, float> y;
};
USTRUCT()
struct FZs
{
GENERATED_USTRUCT_BODY()
FZs() {}
UPROPERTY()
TMap<FString, float> z;
};
USTRUCT()
struct FDataFrame
{
GENERATED_USTRUCT_BODY()
FDataFrame() {}
UPROPERTY()
FLabels labels;
UPROPERTY()
FXs xs;
UPROPERTY()
FYs ys;
UPROPERTY()
FZs zs;
};
Here is the implementation:
FString fcontent = Response->GetContentAsString();
GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, fcontent);
FDataFrame dataframe;
FJsonObjectConverter::JsonObjectStringToUStruct(fcontent, &dataframe, 0, 0);
FLabels labels = dataframe.labels;
FXs xs = dataframe.xs;
FYs ys = dataframe.ys;
FZs zs = dataframe.zs;
TMap<FString, FString> label = labels.label;
TMap<FString, float> x = xs.x;
TMap<FString, float> y = ys.y;
TMap<FString, float> z = zs.z;
However, dataframe
does not get populated.
CodePudding user response:
Another not-working approach is to use a TJsonReader. Here is a stub implementation:
TSharedRef<TJsonReader<>> JsonReader = TJsonReaderFactory<>::Create(Response->GetContentAsString());
TSharedPtr<FJsonObject> JsonObject;
if (FJsonSerializer::Deserialize(JsonReader, JsonObject))
{
TSharedPtr<FJsonObject> labelField = JsonObject->GetObjectField("label");
TMap<FString, TSharedPtr<FJsonValue>> values = labelField->Values;
}
This works so far, but I cannot find out how to proceed with operating on the values.