0

I have a json value like this:

[{"query":[{"number":"0000-2022-64129734 / 19:26"},{"location":"xx"},{"date":"01.06.2022"},{"querytype":"uu"},{"reason":"TEST"},{"identitytype":"xx"}]},{"identity":[{"name":"xx"},{"surname":"xx"},{"id":"xx"},{"mothername":"xx"},{"fathername":"xx"},{"birthlocation":"xx"},{"birthday":"05"},{"birthmonth":"05"},{"birthyear":"1964"},{"birthlocationCity":"xx"}]},{"criminal_record_list":[[{"crime":"xx"},{"value":3}]]}]

and my class is like that:

[JsonObject]
public class CrimeResultModel
{
    [JsonProperty("criminal_record_list")]
    public List<List<criminal_record_list>> criminal_record_list{ get; set; }

    [JsonProperty("query")]
    public List<query> query{ get; set; }

    [JsonProperty("identity")]
    public List<identity> identity{ get; set; }
    public long CriminalRecordType { get; set; }
}



public class criminal_record_list
{
    [JsonProperty("crime")]
    public string crime{ get; set; }

    [JsonProperty("value")]
    public int value{ get; set; }
}

public class query
{
    public string number{ get; set; }
    public string location{ get; set; }
    public string date{ get; set; }
    public string querytype{ get; set; }
    public string reason{ get; set; }
    public string identitytype{ get; set; }

}


public class identity
{
    public string name{ get; set; }
    public string surname{ get; set; }
    public string id{ get; set; }
    public string mothername{ get; set; }
    public string fathername{ get; set; }
    public string birthlocation{ get; set; }

    public string birthday{ get; set; }
    public string birthmonth{ get; set; }
    public string birthyear{ get; set; }
    public string birthlocationCity{ get; set; }
}
}



var result = Newtonsoft.Json.JsonConvert.DeserializeObject<List<CrimeResultModel>>(jsonString);

When i try to deserialize my json, it returns list. And list count is same with property count. every property have their own list as expected but these lists also same count as number of the properties of class.I don't know what to do. Sorry for my English.

Here is the result:

enter image description here

user3188649
  • 139
  • 1
  • 9
  • The JSON is being deserialized according to the model, and the model accounts for the screwy nuances of the structure. What's the problem? – madreflection Jun 01 '22 at 17:06
  • it returns 3 counted list. i expect 1 counted list result. I'm struggling to describe myself :( – user3188649 Jun 01 '22 at 17:10
  • Your expectation is incorrect. – madreflection Jun 01 '22 at 17:10
  • what should i to to have this result? – user3188649 Jun 01 '22 at 17:11
  • Let me clarify "screwy nuances": I mean that what you have is a 3-tuple of `query`, `identity`, and `criminal_record_list`, containers but tuples are not a first-class feature in JSON so it's represented as an array of objects where each one has just one of those properties, in order. In order to get `query`, you need `asbsResult[0].query`. To get `identity`, you need `asbsResult[1].identity`, and so on. That's the structure defined by the JSON, and so it's the structure of your C# classes. – madreflection Jun 01 '22 at 17:12
  • each item have query, criminal_record_list and identity properties. I need one item which has query, criminal_record_list and identity properties – user3188649 Jun 01 '22 at 17:12
  • *"each item have query, criminal_record_list and identity properties"* - That is incorrect. – madreflection Jun 01 '22 at 17:14
  • i can see how to get identity value from this list result. But it is not what i want. I need something like that: identity=asbsResult[0].identity , query=asbsResult[0].query – user3188649 Jun 01 '22 at 17:15
  • Do you have control over the JSON structure? Or are you getting this from somewhere else that defines its structure? – madreflection Jun 01 '22 at 17:15
  • No i don't have control over json – user3188649 Jun 01 '22 at 17:17

2 Answers2

0

try this

    json = json.Replace("},{", ",");

    var jsonArr = JArray.Parse(json);
    Data data = new Data
    {
        Query = ((JObject)jsonArr[0]).Properties().Where(p => p.Name == "query").First().Value.First.ToObject<query>(),
        Identity = ((JObject)jsonArr[0]).Properties().Where(p => p.Name == "identity").First().Value.First.ToObject<identity>(),
        CriminalRecordList = ((JObject)jsonArr[0]).Properties().Where(p => p.Name == "criminal_record_list").First().Value.First.ToObject<List<criminal_record_list>>()
    };

class Data

public class Data
{
    public Query Query { get; set; }
    public Identity Identity { get; set; }
    public List<criminal_record_list> CriminalRecordList { get; set; }
}

Serge
  • 40,935
  • 4
  • 18
  • 45
0

Your situation is very similar to the one from Serialize list of objects with string properties to json array of objects: your JSON contains arrays of single-property objects, and you would like to map those array to POCOs with multiple properties corresponding to the singleton properties in the corresponding array of objects. Your situation differs only in that every type of object in your JSON is represented as an array of objects, rather than just one type.

Thus you can generalize ObjectAsObjectArrayConverter<TObject> from this answer to handle all c# types that will be serialized as JSON objects, then use it to deserialize your JSON.

First, define the following custom JsonConverter:

public class ObjectAsObjectArrayConverter : JsonConverter
{
    // Generalized from this answer https://stackoverflow.com/a/72354204/3744182
    // By https://stackoverflow.com/users/3744182/dbc
    // To https://stackoverflow.com/questions/72352865/serialize-list-of-objects-with-string-properties-to-json-array-of-objects
    static IContractResolver DefaultResolver { get; } = JsonSerializer.Create().ContractResolver;
    readonly IContractResolver resolver;

    public ObjectAsObjectArrayConverter() : this(DefaultResolver) { }
    public ObjectAsObjectArrayConverter(IContractResolver resolver) => this.resolver = resolver ?? throw new ArgumentNullException(nameof(resolver));

    public override bool CanConvert(Type objectType)
    {
        if (objectType.IsPrimitive || objectType == typeof(string))
            return false;
        if (!(resolver.ResolveContract(objectType) is JsonObjectContract contract))
            return false;
        if (contract.DefaultCreator == null)
            return false;
        return true;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var contract = (serializer.ContractResolver.ResolveContract(value.GetType()) as JsonObjectContract) ?? throw new ArgumentException("Wrong contract type");
        writer.WriteStartArray();
        foreach (var property in contract.Properties.Where(p => ShouldSerialize(p, value)))
        {
            var propertyValue = property.ValueProvider.GetValue(value);
            if (propertyValue == null && (serializer.NullValueHandling == NullValueHandling.Ignore || property.NullValueHandling == NullValueHandling.Ignore))
                continue;
            writer.WriteStartObject();
            writer.WritePropertyName(property.PropertyName);
            if (propertyValue == null)
                writer.WriteNull();
            else if (property.Converter != null && property.Converter.CanWrite)
                property.Converter.WriteJson(writer, propertyValue, serializer);
            else
                serializer.Serialize(writer, propertyValue);
            writer.WriteEndObject();
        }
        writer.WriteEndArray();
    }

    protected virtual bool ShouldSerialize(JsonProperty property, object value) =>
        property.Readable && !property.Ignored && (property.ShouldSerialize == null || property.ShouldSerialize(value));

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (existingValue == null)
            existingValue = serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();

        switch (reader.MoveToContentAndAssert().TokenType)
        {
            case JsonToken.Null:
                return (object)null;
        
            case JsonToken.StartArray:
                while (reader.ReadToContentAndAssert().TokenType != JsonToken.EndArray)
                {
                    switch (reader.TokenType)
                    {
                        case JsonToken.StartObject:
                            serializer.Populate(reader, existingValue);
                            break;
                        default:
                            throw new JsonSerializationException("Unexpected token type " + reader.TokenType.ToString());
                    }
                }
                break;

            case JsonToken.StartObject:
                serializer.Populate(reader, existingValue);
                break;

            default:
                throw new JsonSerializationException("Unexpected token type " + reader.TokenType.ToString());
        }
        return existingValue;
    }
}

public static partial class JsonExtensions
{
    public static JsonReader ReadToContentAndAssert(this JsonReader reader) =>
        reader.ReadAndAssert().MoveToContentAndAssert();

    public static JsonReader MoveToContentAndAssert(this JsonReader reader)
    {
        if (reader == null)
            throw new ArgumentNullException();
        if (reader.TokenType == JsonToken.None)       // Skip past beginning of stream.
            reader.ReadAndAssert();
        while (reader.TokenType == JsonToken.Comment) // Skip past comments.
            reader.ReadAndAssert();
        return reader;
    }

    public static JsonReader ReadAndAssert(this JsonReader reader)
    {
        if (reader == null)
            throw new ArgumentNullException();
        if (!reader.Read())
            throw new JsonReaderException("Unexpected end of JSON stream.");
        return reader;
    }
}

Next, modify your CrimeResultModel as follows, leaving criminal_record_list, query and identity unchanged:

public class CrimeResultModel
{
    [JsonProperty("criminal_record_list")]
    public List<criminal_record_list> criminal_record_list{ get; set; }

    [JsonProperty("query")]
    public query query{ get; set; }

    [JsonProperty("identity")]
    public identity identity { get; set; }
    
    public long CriminalRecordType { get; set; }
}

And now you will be able to do:

var inputSettings = new JsonSerializerSettings
{
    Converters = { new ObjectAsObjectArrayConverter() },
};
var result = JsonConvert.DeserializeObject<CrimeResultModel>(jsonString, inputSettings);

Demo fiddle here.

dbc
  • 104,963
  • 20
  • 228
  • 340