Ian
Ian

Reputation: 323

JSON Deserialize different named object into a Collection c#

I have to read a given JSON string into C# objects. So far so good but this case is kind of special to me. The JSON string contains 2 entities. One is a flat object and the second is a list, logical at least but not really in JSON. I hope you can help me finding a solution to this.

To explain it better i will show you a part of my JSON input:

{
"game":{"GameMode":"1","IsNetworkMode":"1","NbMaxPlayer":"12","GameState":"1"},

"player_56":{"PlayerUserId":"137187","PlayerIALevel":"-1","PlayerObserver":"0"},
"player_7":{"PlayerUserId":"3440","PlayerIALevel":"-1","PlayerObserver":"0"}
}

I want to serialize the Player entities into a collection of objects of this type. The Problem is that they arent really stored as a collection in JSON. They have dynamic names as "player_56" and the number is not in any logical order like "1,2,3".

At the moment I am using the DataContractJsonSerializer for this task.

[DataContract]
public class AlbReplay
{
    [DataMember(Name = "game")]
    public AlbGame Game { get; set; }
    [DataMember(Name = "player")]
    public List<AlbPlayer> Players { get; set; }
}

Any suggestions?

Upvotes: 2

Views: 301

Answers (2)

Louis Ricci
Louis Ricci

Reputation: 21106

Mangle your JSON into a collection of player objects.

player_8: {...}
player_99: {...}

to

players: [
    {id: 8 ...},
    {id: 99 ...}
]

How to mangle your JSON, a RegEx would likely be sufficient.

EDIT Here's code for the string mangling using Regex. A few assumptions were made: there are no objects embedded inside of the game and player objects and the player object list is the last part of the json string.

        string json_test = @"{
""game"":{""GameMode"":""1"",""IsNetworkMode"":""1"",""NbMaxPlayer"":""12"",""GameState"":""1""},
""player_56"" : {""PlayerUserId"":""137187"",""PlayerIALevel"":""-1"",""PlayerObserver"":""0""},
""player_2"":  {""PlayerUserId"":""137187"",""PlayerIALevel"":""-1"",""PlayerObserver"":""0""}
}";
        json_test = new Regex(@"""player_(\d+)""\s*:\s*{").Replace(json_test, @"""player"" : {""Id"": $1,");
        Console.WriteLine("player_##:{...} -> player:{id: ##,..}");
        Console.WriteLine(json_test);
        json_test = new Regex(@"""player""\s*:\s*{").Replace(json_test, @"""players"" : [{", 1);
        json_test = new Regex(@"""player""\s*:\s*{").Replace(json_test, @"{");
        json_test = new Regex(@"}$").Replace(json_test, @"]}");
        Console.WriteLine("player:{...}, -> players: [{...},...]");
        Console.WriteLine(json_test);

As with all considerations regarding speed, you'll have to test it out, having the Regex objects as static and reusable would be my first step if I had to optimize the above.

Upvotes: 1

Dustin Kingen
Dustin Kingen

Reputation: 21265

I don't know the extent of DataContractJsonSerializer, but there might be an interface you can implement on your class to define how to parse the JSON.

But if you're able to use JSON.Net:

public class Player
{
    public int Id { get; set; }
    public int PlayerUserId { get; set; }
    public int PlayerIALevel { get; set; }
    public int PlayerObserver { get; set; }
}

And then you can use Linq-To-JSON:

var data = @"{
""game"":{""GameMode"":""1"",""IsNetworkMode"":""1"",""NbMaxPlayer"":""12"",""GameState"":""1""},

""player_56"":{""PlayerUserId"":""137187"",""PlayerIALevel"":""-1"",""PlayerObserver"":""0""},
""player_7"":{""PlayerUserId"":""3440"",""PlayerIALevel"":""-1"",""PlayerObserver"":""0""}
}";

JObject o = JObject.Parse(data);

IEnumerable<Player> players =
    o.Children()
    .Where(p => ((JProperty)p).Name.StartsWith("player"))
    .Select(p =>
        new Player
        {
            Id = int.Parse(((JProperty)p).Name.Split('_')[1]),
            PlayerUserId = int.Parse((string)p.Children<JObject>().First()["PlayerUserId"]),
            PlayerIALevel = int.Parse((string)p.Children<JObject>().First()["PlayerIALevel"]),
            PlayerObserver = int.Parse((string)p.Children<JObject>().First()["PlayerObserver"]),
        });

Upvotes: 1

Related Questions