【问题标题】:How to iterate through a JSON response with nested arrays/lists如何使用嵌套数组/列表遍历 JSON 响应
【发布时间】:2021-08-22 07:48:06
【问题描述】:

我正在开发一个 API 返回带有嵌套数组对象的 JSON 响应的项目​​。我试图循环获取最里面的字符串(十六进制)项目数组。但该项目显示为空。

这是 JSON 响应:我正在尝试访问下面的主要部分,这是一个字符串十六进制字节数组。

{   // The main response
    "Success": true,
    "Total": 49,
    "TotalPages": 49,
    "ModesList": [
        {
            "Id": 1058,
            "Name": "kharabeesh",
            "Order": 0,
            "StepOneTime": "2.03s",
            "UserId": 1015,
            "IsPublic": true,
            "User": "Sahar M",
            "Date": "02/06/2021",
            "Mode": [ // I'm trying to access this part
                [
                    "16",
                    "1",
                    "1",
                    "0",
                    "5",
                    "71",
                    "255",
                    "255",
                    "255",
                    "76",
                    "20"
                ],
                [
                    "16",
                    "2",
                    "1",
                    "6",
                    "53",
                    "71",
                    "76",
                    "3",
                    "33",
                    "0",
                    "17"
                ],
                [
                    "16",
                    "3",
                    "1",
                    "6",
                    "53",
                    "71",
                    "73",
                    "127",
                    "87",
                    "0",
                    "17"
                ],
                [
                    "16",
                    "4",
                    "1",
                    "7",
                    "181",
                    "127",
                    "127",
                    "119",
                    "45",
                    "0",
                    "17"
                ],
                [
                    "16",
                    "5",
                    "1",
                    "0",
                    "7",
                    "192",
                    "170",
                    "48",
                    "11",
                    "0",
                    "32"
                ],
                [
                    "16",
                    "6",
                    "1",
                    "7",
                    "130",
                    "15",
                    "67",
                    "71",
                    "170",
                    "0",
                    "32"
                ],
                [
                    "16",
                    "7",
                    "1",
                    "0",
                    "67",
                    "8",
                    "206",
                    "45",
                    "195",
                    "0",
                    "68"
                ]
            ]
        }
    ]
}

这是我目前所拥有的:

public class GetModesResponse
    {
        public bool Success;
        public long Total;
        public long TotalPages;
        public List<ModesList>[] ModesList;
    }

    public class ModesList
    {
        public long Id;
        public string Name;
        public long Order;
        public string StepOneTime;
        public long UserId;
        public bool IsPublic;
        public string User;
        public string Date;
        public List<long>[] Mode;
    }

private void PopulateModes(GetModesResponse publicModes)
    {
        var allModes = publicModes.ModesList;
        var index = 0;
        foreach(var mode in allModes[0])
        {
            Debug.Log(mode.Name);
            var modeItem = Instantiate(ModeItemPrefab, ModeContainer.transform);
            var usedColors = new List<Color>();
            var steps = mode.Mode[0];
            Debug.Log(steps[0]);
            var stepColor = mainScript.GetColor((byte) steps[6], (byte) steps[7], (byte) steps[8], (byte) steps[9], 0);
            if (!usedColors.Contains(stepColor))
            {
                usedColors.Add(stepColor);
            }
            modeItem.Initialize(index, (int) mode.Id, mode.Name, mode.User, usedColors, this);
        }
    }

更新

这是我从 API 获取 JSON 后调用填充函数的方式:

private IEnumerator GetPublicModes()
    {
        WWWForm form = new WWWForm();
        form.AddField("keyword", "");
        form.AddField("size", 1000);
        form.AddField("pageNo", 1);
        
        using (UnityWebRequest www = UnityWebRequest.Post(Manager.ApiUrlBase + "GetModes", form))
        {
            yield return www.SendWebRequest();
            if (!www.isDone)
            {
                Debug.Log(www.error);
            }
            else
            {
                var response = www.downloadHandler.text;
                Debug.Log("Get Modes complete!");
                GetModesResponse getModesResponse = new GetModesResponse();
                getModesResponse = JsonUtility.FromJson<GetModesResponse>(response);
                Debug.Log(getModesResponse.ToString());
                if (getModesResponse.Success)
                {
                    //Populate List
                    gottenModes = getModesResponse;
                    PopulateModes(getModesResponse);
                    
                }
                else
                {
                    // Display Error Message
                    Debug.Log(response);
                }
            }
        }
    }

更新解决方案: 感谢@MajidMohammadi、@AttilaMolnar、@A____ 和 @derHugo 的帮助。 @derHugo 通过转到https://json2csharp.com/ 帮助我找到了答案,它终于奏效了。这是我最后的做法:

[Serializable] 
    public class ModesList
    {
        public ModesList(
            int id,
            string name,
            int order,
            string stepOneTime,
            int userId,
            bool isPublic,
            string user,
            string date,
            List<List<string>> mode
        )
        {
            this.Id = id;
            this.Name = name;
            this.Order = order;
            this.StepOneTime = stepOneTime;
            this.UserId = userId;
            this.IsPublic = isPublic;
            this.User = user;
            this.Date = date;
            this.Mode = mode;
        }

        public int Id;
        public string Name;
        public int Order;
        public string StepOneTime;
        public int UserId;
        public bool IsPublic;
        public string User;
        public string Date;
        public List<List<string>> Mode;
    }

    [Serializable]
    public class GetModesResponse
    {
        public GetModesResponse(
            bool success,
            int total,
            int totalPages,
            List<ModesList> modesList
        )
        {
            this.Success = success;
            this.Total = total;
            this.TotalPages = totalPages;
            this.ModesList = modesList;
        }

        public bool Success;
        public int Total;
        public int TotalPages;
        public List<ModesList> ModesList;
    }

【问题讨论】:

  • 您是否尝试过将 Mode 属性的类型更改为字节数组(=byte[ ])?
  • 不,我没有,看起来怎么样?
  • 在我看到你的代码之后,我得出的结论是,你可能需要将 Mode 属性的类型更改为 byte[ ][ ](= array of byte array) 的类型。我希望它能解决问题。
  • 谢谢@Majid Mohammadi,但不幸的是,这并没有改变任何事情。我仍然收到此错误:NullReferenceException: Object reference not set to an instance of an object GalleryPanelScript.PopulateModes (GalleryPanelScript+GetModesResponse publicModes) (at Assets/Scripts/GalleryPanelScript.cs:83) 这是代码的这一部分:foreach(var mode in allModes[0])
  • 我认为,public List&lt;ModesList&gt;[] ModesList; 应该只是 public List&lt;ModesList&gt; ModesList;,因为 ModeList 只是一个简单的列表而不是嵌套列表。当你在另一个模型public List&lt;long&gt;[] Mode; 中指定这个时,我不确定它是否正确,因为数字在撇号 (") 中,所以从 JSON 语法视图来看,它们必须是不长的字符串(除非你没有任何转换功能用于该记录)。我会以这种方式指定它:public List&lt;List&lt;string&gt;&gt; Mode;

标签: c# arrays json unity3d object


【解决方案1】:

一般来说,要使用 Unity,您的类应标记为 [Serializable]。详情请见Unity Script Serialization

然后,您在 JSON 中的内容不是 List&lt;long&gt;[],而是 List&lt;string&gt;[] 或只是 List&lt;List&lt;string&gt;&gt;,因为您的数字包含在 " 中!

所以你的班级应该看起来像例如(json2csharp 通常提供了一个非常可靠的起点,只需要少量采用即可使用 Unity 序列化程序)

[Serializable]
public class ModesList
{
    public int Id;
    public string Name;
    public int Order;
    public string StepOneTime;
    public int UserId;
    public bool IsPublic;
    public string User;
    public string Date;
    public List<List<string>> Mode;
}

[Serializable]
public class GetModesResult
{
    public bool Success;
    public int Total;
    public int TotalPages;
    public List<ModesList> ModesList;
}

然后你会使用byte.Parse,例如

var stepColor = mainScript.GetColor(byte.Parse(steps[6]), byte.Parse(steps[7]), byte.Parse(steps[8]), byte.Parse(steps[9]), 0);
      

但是,现在只能在手机上进行,所以无法测试,但要进一步

注意:Unity 不支持多级类型(多维数组、交错数组和嵌套容器类型)的序列化。如果你想序列化这些,你有两个选择:将嵌套类型包装在一个类或结构中,或者使用序列化回调ISerializationCallbackReceiver 来执行自定义序列化。有关详细信息,请参阅Custom Serialization 上的文档。

【讨论】:

  • 感谢您的回答,但随后我收到错误消息:NullReferenceException:对象引用未设置为对象的实例。那么我该如何解决呢?
  • 当我遍历 ModesList.Mode 并放置 Debug.Log(step[0]) 时,它会在控制台中打印 Null 7 次。所以我无法获取模式列表中的属性
【解决方案2】:

我认为你应该改变 JSON 的结构。

我在本地测试过:

JSON 文件

{   
    "Success": true,
    "Total": 49,
    "TotalPages": 49,
    "ModesList": [
        {
            "Id": 1058,
            "Name": "kharabeesh",
            "Order": 0,
            "StepOneTime": "2.03s",
            "UserId": 1015,
            "IsPublic": true,
            "User": "Sahar M",
            "Date": "02/06/2021",
            "Mode": [
                {
                    "Value":
                    [   
                        "16",
                        "1",
                        "1",
                        "0",
                        "5",
                        "71",
                        "255",
                        "255",
                        "255",
                        "76",
                        "20"
                    ]   
                },
                {
                    "Value":
                    [    
                        "16",
                        "2",
                        "1",
                        "6",
                        "53",
                        "71",
                        "76",
                        "3",
                        "33",
                        "0",
                        "17"
                    ]   
                }
            ]
        }
    ]
}

DataModuleClass(C#)


[Serializable]
public class XXXDataModule
{
    public bool Success;
    public int Total;
    public int TotalPage;

    public List<ModesList> ModesList;

    public XXXDataModule()
    {
    }

}


[Serializable]
public class ModesList
{
    public int Id;
    public string Name;
    public int Order;
    public string StepOneTime;
    public int UserId;
    public bool IsPublic;
    public string User;
    public string Date;
    public List<Mode> Mode;

    public ModesList()
    {
        
    }
}


[Serializable]
public class Mode
{
    public Mode()
    {
        
    }

    public List<string> Value;
}

反序列化(C#)


    public void OnClickJsonParse()
    {
        // I just simulated the reading of the data locally
        var jsonText = File.ReadAllText(Application.streamingAssetsPath + "/LitJson4Unity.json");
        Debug.Log("jsonText " + jsonText);

        //JsonData json = JsonMapper.ToObject(jsonText);

        // Use LitJson
        //XXXDataModule jsonData = JsonMapper.ToObject<XXXDataModule>(jsonText);

        // Use Unity JSONSerializeModule
        XXXDataModule jsonData = JsonUtility.FromJson<XXXDataModule>(jsonText);

        Debug.Log(jsonData.ModesList[0].Mode[0].Value[0]);

    }

VS Debug

【讨论】:

  • 当您有服务器 API 时,更改 JSON 通常不是一种选择;)
  • 就我而言,可能很难更改
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-30
  • 1970-01-01
  • 1970-01-01
  • 2021-08-18
  • 2010-12-06
  • 1970-01-01
  • 2019-08-22
相关资源
最近更新 更多