Reputation: 323
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
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
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