0

{ "check":"success", "stats":{ "2":{ "rank":1, "score":"2000", "name":"Muhammad" }, "3":{ "rank":1, "score":"2000", "name":"Ramsay" }}}

this is my json string. I want to use "stats" as a list to check how many entries it has. Then I need to get the rank, name, score etc from each entry. My code is,

var result = Json.Deserialize(jsontest) as Dictionary<string,object>;
    object st;
    var rankholders = new List<object>();
    if (result.TryGetValue("stats", out st))
    {
        rankholders = (List<object>)(((Dictionary<string, object>)st)["stats"]);
        foreach (object obj in rankholders)
        {
            var tempDict = ((Dictionary<string,object>)(rankholders[0]));
            WeeklyStatsItem tempRow = new WeeklyStatsItem ();
            tempRow.rank = (string)tempDict["rank"];
            tempRow.name = (string)tempDict["name"];
            tempRow.score = (string)tempDict["score"];
            weeklyScoreList.Add (tempRow);
        }
    }

But I get keynotfound exception. Any idea how to parse such a json loop?

ree1991
  • 197
  • 1
  • 1
  • 20
  • Do you have any insight into what the keys in stat's value dictionary are? I'm referring to the "2" and "3" in your example. Their values seem to represent a Player object or something like that, but I'm not sure what it's keyed on which could help when making a server side data structure. – 2manyprojects Jun 14 '16 at 00:47
  • @2manyprojects I have added 2,3 etc now. But those will be values that represent the user ids. – ree1991 Jun 14 '16 at 04:07
  • Ok, I think I've got it. If you've got experience with MiniJSON I suspect my answer can be improved. Feel free to make suggestions. – 2manyprojects Jun 15 '16 at 19:07

3 Answers3

0

To me it looks like you have an object which contains a property "check" and a dictionary called "stats". If you will make your own class having this structure, you will be able to deserialize json to this type of object Something like:

class Stats
{
public int rank;
public int score;
public string name;
}

class ResultContainer
{
public string checked;
public Dictionary<int,Stats>stats;
}

And you should deserialize as ResultContainer.

meJustAndrew
  • 6,011
  • 8
  • 50
  • 76
-1

Your Json is NOT valid because it was throwing error when stats is made to be a List or array. I was able to re-create a valid Json with the code below:

I want to use "stats" as a list to check how many entries it has

WeeklyStatsItem recreation = new WeeklyStatsItem();
recreation.check = "success";

recreation.stats = new List<Stats>();

Stats st1 = new Stats();
st1.rank = 1;
st1.score = "2000";
st1.name = "Muhammad";
recreation.stats.Add(st1);

Stats st2 = new Stats();
st2.rank = 1;
st2.score = "2000";
st2.name = "Ramsay";
recreation.stats.Add(st2);

Debug.Log(JsonUtility.ToJson(recreation));

The new generated valid Json is:

{"check":"success","stats":[{"rank":1,"score":"2000","name":"Muhammad"},{"rank":1,"score":"2000","name":"Ramsay"}]}

Now to answer your question:

I want to use "stats" as a list to check how many entries it has.

string jsonTest = "{\"check\":\"success\",\"stats\":[{\"rank\":1,\"score\":\"2000\",\"name\":\"Muhammad\"},{\"rank\":1,\"score\":\"2000\",\"name\":\"Ramsay\"}]}";
WeeklyStatsItem weeklyIt = JsonUtility.FromJson<WeeklyStatsItem>(jsonTest);
Debug.Log(weeklyIt.stats.Count);

Then I need to get the rank, name, score etc from each entry

string jsonTest = "{\"check\":\"success\",\"stats\":[{\"rank\":1,\"score\":\"2000\",\"name\":\"Muhammad\"},{\"rank\":1,\"score\":\"2000\",\"name\":\"Ramsay\"}]}";
WeeklyStatsItem weeklyIt = JsonUtility.FromJson<WeeklyStatsItem>(jsonTest);

Debug.Log("CHECK: " + weeklyIt.check);
for (int i = 0; i < weeklyIt.stats.Count; i++)
{
    Debug.Log("STATS INDEX: " + i);
    Debug.Log("RANK: " + weeklyIt.stats[i].rank);
    Debug.Log("NAME: " + weeklyIt.stats[i].name);
    Debug.Log("SCORE: " + weeklyIt.stats[i].score);
}

Your Json Classes:

[Serializable]
public class Stats
{
    public int rank;
    public string score;
    public string name;
}

[Serializable]
public class WeeklyStatsItem
{
    public string check;
    public List<Stats> stats;
}
Programmer
  • 121,791
  • 22
  • 236
  • 328
  • I understand your logic. But it is not possible for me to change the JSON format. Any idea how I can parse it by changing the code on my end only? – ree1991 Jun 13 '16 at 07:40
  • @ree1991 You talked about getting stats as a list but stats is not a list in the json you have. Not only that, there are problems with your json format. I am not not kidding when I say that. You need to ask the server programmer to change the json format to what is listed in my answer. Why can't you change the JSON format? – Programmer Jun 13 '16 at 07:57
  • Right now the server side cannot be changed, and unfortunately they will not be revising the format for at least a few months. So i'm trying to find a way to parse this very format and get the data as i need. Thanks for your help though. I will try to parse the stats data as a list, but i am at a loss with those extra ids, "2", "3" etc – ree1991 Jun 13 '16 at 08:01
  • @ree1991 **they will not be revising the format for at least a few months** it looks like you are working with the wrong people if they can't fix what's wrong within a day. All they have to do is fix the format they are sending these. If they can't do this is 10 minutes so that you can continue with your work then there is a problem with the team. Even if you find a workaround for this, the format is bad and must be fixed. Anyways, good luck. – Programmer Jun 13 '16 at 08:09
  • @Programmer The json is valid, use any validator to check it. I prefer JsonLint: http://jsonlint.com/ – 2manyprojects Jun 14 '16 at 00:40
  • 1
    @2manyprojects before you downvote next time make sure to read the comment and also make sure to understand what's going on. In terms of what he's trying to do, his json is not valid for that because he want's `stats` to be a list or array. Array/list is '[' ']'. Again, his `stats` cannot be a list. that's we are both getting an exception. Now copy the json in his question and paste to http://json2csharp.com/ You will see invalid stuff. Copy the fixed json from my answer to http://json2csharp.com/ and you will see what his json should look like. – Programmer Jun 14 '16 at 05:18
-1

Since you're keys have semantic meaning and don't map to variable names you'll have to go a bit further than the basic examples that assume your json objects map neatly to a c# object, i.e. that they have a fixed schema.

Basically you'll have to look at each entry in the stats dict and pass both the key and the underlying values to your domain object constructor.

I'm not super familiar with MiniJSON, but I've banged together a working example. I suspect there is a more idiomatic way of doing this, e.g. using generics.

Assets/Editor/ParserTest.cs


using NUnit.Framework;

public class ParserTest {

    [Test]
    public void TestThatTwoPlayersAreInTestResponse()
    {
        string testResponse = "{ \"check\":\"success\", \"stats\":{ \"2\":{ \"rank\":1, \"score\":\"2000\", \"name\":\"Muhammad\" }, \"3\":{ \"rank\":1, \"score\":\"2000\", \"name\":\"Ramsay\" } } }";
        Assert.AreEqual(MiniJsonParsingExample.parseResponse(testResponse).Count, 2);
    }
}

Assets/Scripts/MiniJsonParsingExample.cs


using System.Collections.Generic;
using Facebook.MiniJSON;

public class MiniJsonParsingExample
{

    public static List parseResponse(string responseText)
    {
        var resultDict = Json.Deserialize(responseText) as Dictionary;
        var players = new List();
        if (resultDict.ContainsKey("stats"))
        {
            var playerDict = resultDict["stats"] as Dictionary;
            foreach (string playerId in playerDict.Keys)
            {
                var psuedoPlayer = playerDict[playerId] as Dictionary;
                string playerName = psuedoPlayer["name"] as string;
                long playerRank = (long) psuedoPlayer["rank"];
                string playerScore = psuedoPlayer["score"] as string;
                players.Add(new Player(playerId, playerName, playerRank, playerScore));
            }
        }
        return players;
    }

    public class Player
    {
        string id;
        string name;
        long rank;
        string score;

        public Player(string id, string name, long rank, string score)
        {
            this.id = id;
            this.name = name;
            this.rank = rank;
            this.score = score;
        }
    }
}

2manyprojects
  • 845
  • 7
  • 14