An alternative method, using a class object that defines each group of properties that have a common prefix as a Dictionary<string, TValue>
.
The JSON is deserialized using a custom JsonConverter that maps each group of properties in the JSON to a Property of the class, using a Dictionary<string, string>
:
Dictionary<string, string> map = new Dictionary<string, string>() {
["Descriptions"] = "descriptions_",
["OfficialTitles"] = "official_title_",
["AuthTowns"] = "auth_town_"
};
All properties in the JSON that map to a Property in the class are added to the corresponding Dictionary and the values converted to the Type defined by the class property.
Note: you need to adapt the mapper and class Properties to the JSON. You could make the procedure more generic using some logic to determine when Property Name in the JSON belongs to the same group and generate a new Dictionary<string, TValue>
to add to the class by reflection.
Or simply add more Properties to the class off-line, if you find other groups.
Call it as:
(possibly giving the class a less silly name :)
var result = new SimpleSequences().Deserialize(json);
Helper class object:
private class SimpleSequences
{
public SimpleSequences() {
Descriptions = new Dictionary<string, long[]>();
OfficialTitles = new Dictionary<string, string>();
AuthTowns = new Dictionary<string, string>();
}
public List<SimpleSequences> Deserialize(string json)
{
var options = new JsonSerializerSettings() {
Converters = new[] { new SimpleSequencesConverter() }
};
return JsonConvert.DeserializeObject<List<SimpleSequences>>(json, options);
}
public int Id { get; set; }
public Dictionary<string, long[]> Descriptions { get; set; }
public Dictionary<string, string> OfficialTitles { get; set; }
public Dictionary<string, string> AuthTowns { get; set; }
}
Custom JsonConverter:
This converter handles a single object or array of objects (as shown in your question), but always return a List<SimpleSequences>
(which may contain a single object). Modify as required.
public class SimpleSequencesConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => true;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType != JsonToken.StartArray && reader.TokenType != JsonToken.StartObject) {
throw new Exception($"Unexpected Type. Expecting Array or Object, got {reader.TokenType}");
}
var elementsList = new List<SimpleSequences>();
if (reader.TokenType == JsonToken.StartObject) {
elementsList.Add(GetPropertyValues(JObject.Load(reader)));
}
else {
while (reader.Read() && reader.TokenType != JsonToken.EndArray) {
elementsList.Add(GetPropertyValues(JObject.Load(reader)));
}
}
return elementsList;
}
private SimpleSequences GetPropertyValues(JToken token)
{
var element = new SimpleSequences();
element.Id = token["id"].ToObject<int>();
var descriptions = token.Children().Where(t => t.Path.StartsWith(map["Descriptions"]));
foreach (JProperty p in descriptions) {
element.Descriptions.Add(p.Path, p.Value.ToObject<long[]>());
}
var titles = token.Children().Where(t => t.Path.StartsWith(map["OfficialTitles"]));
foreach (JProperty p in titles) {
element.OfficialTitles.Add(p.Path, p.Value.ToString());
}
var authTowns = token.OfType<JToken>().Where(t => t.Path.StartsWith(map["AuthTowns"]));
foreach (JProperty p in authTowns) {
element.AuthTowns.Add(p.Path, p.Value.ToString());
}
return element;
}
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
=> throw new NotImplementedException();
Dictionary<string, string> map = new Dictionary<string, string>() {
["Descriptions"] = "descriptions_",
["OfficialTitles"] = "official_title_",
["AuthTowns"] = "auth_town_"
};
}