虚幻引擎4中的C++嵌套JSON

9

我有一个从服务器获取的JSON对象,看起来像这样:

{
    "state":"1",
    "player1": {
        "alias":"Player Name",
        "ready":"0"
    }
}

我可以获取JSON,将其解析为FJsonObject,并使用以下代码进行序列化以检索JSON对象的第一级中的任何数字或字符串:

TSharedPtr<FJsonObject> JsonParsed;
TSharedRef<TJsonReader<TCHAR>> JsonReader = TJsonReaderFactory<TCHAR>::Create(json);
if (FJsonSerializer::Deserialize(JsonReader, JsonParsed))
    //Use JsonParsed

以下是用于读取字符串的代码:

FString AJSONContainer::getStringWithKey(FString key)
{
    return storedJSON->GetStringField(key);
}    

旁注:

AJSONContainer只是一个我用来从蓝图中调用这些函数的Actor类。


这很好,但是当我尝试从第二层读取内容时,事情就不顺利了。

我编写了以下代码以获取下一级:

TSharedPtr<FJsonObject> nested = storedJSON->GetObjectField(key);

但是获取nested字段的所有调用都没有返回任何结果。

nested->GetStringField(anotherKey); //Nothing

因此,以上述JSON为例,这个:
TSharedPtr<FJsonObject> nested = storedJSON->GetObjectField("player1");
FString alias = nested->GetStringField("alias");

当我将alias控制台输出时,它没有值。


我做错了什么吗?为什么第二级JSON不起作用?


调用 GetField<EJson::Object> 而不是 GetObjectField 可以轻松解决问题。它将为您获取一个 JsonValue,您可以使用 FJsonValue::AsObject 方法将其转换为 FJsonValue - Santiago
3个回答

22

不知道你是否已经解决了问题,但我找到了一个相当恶心的函数,可以处理嵌套对象和整个数组。它会给你一个USTRUCT,因此你不必使用通过键获取值的函数(我不喜欢它们,因为它们非常容易出错)。相反,你会拥有类型安全性!

FJsonObjectConverter::JsonObjectStringToUStruct

这里是文档和另一个在UE4 AnswerHub上回答的问题。

基本上,你创建目标USTRUCT(或用于嵌套JSON的多个USTRUCTs),使用UPROPERTY标记所有属性,以便Unreal知道它们的名称,并使用此函数。它将通过匹配复制值。它甚至可以复制数组! =D

示例

我将要反序列化的JSON FString称为Json,它的结构如下所示。它包含一个嵌套对象和一个数组,让事情变得有趣。

{
    "nested" : {
        "id" : "654asdf",
        "name" : "The Name"
    },
    "foo" : "foobar",
    "bar_arr" : [
        { "barfoo" : "asdf" },
        { "barfoo" : "qwer" }
    ]
}

在转换之前,我们需要从内到外创建USTRUCTs(这样我们就可以在外部引用内部)。记得始终使用F作为结构体名称。

USTRUCT()
struct FNested
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY()
    FString id;

    UPROPERTY()
    FString name;
};

USTRUCT()
struct FBar
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY()
    FString barfoo;
};

USTRUCT()
struct FJsonData
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY()
    FNested nested;

    UPROPERTY()
    FString foo;

    UPROPERTY()
    TArray<FBar> bar_arr;
};

转换将会如下进行:
FJsonData JsonData;
FJsonObjectConverter::JsonObjectStringToUStruct<FJsonData>(
    Json,
    &JsonData,
    0, 0);

现在,您可以像使用标准的C++结构体一样访问所有属性。例如,要访问其中一个barfoo
FString barfoo0 = JsonData.bar_arr[0].barfoo;

我还没有在JSON中测试过int和float,但是由于它甚至可以复制数组,所以我认为这也会起作用。

0
    for (auto currJsonValue = JsonObject->Values.CreateConstIterator(); currJsonValue; ++currJsonValue)
    {
        // Get the key name
        const FString Name = (*currJsonValue).Key;

        // Get the value as a FJsonValue object
        TSharedPtr< FJsonValue > Value = (*currJsonValue).Value;

        TSharedPtr<FJsonObject> JsonObjectIn = Value->AsObject();
    }

可以通过GetObjectField或我发布的代码访问嵌套的Json对象。


0

正如我所评论的,调用GetField<EJson::Object>而不是GetObjectField是解决方案。

因此,这段代码将获取您的嵌套JSON:

TSharedPtr<FJsonValue> nested = storedJSON->GetField<EJson::Object>("player1");
TSharedPtr<FJsonObject> nestedParsed = nested->AsObject();
FString alias = nestedParsed->GetStringField("alias"); // alias == "Player Name"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接