0

I am attempting to deserialize a piece of JSON with a specific structure like so:

{  
    "label1": "value1",  
    "label2": [  
        [  
            [  
                "concept_id_1",  
                "concept_1"  
            ],  
            score_1  
        ],  
        [  
            [  
                "concept_id_2",  
                "concept_2"  
            ],  
            score_2  
        ],  
        ……  
    ],  
    "label3": "value3",  
    "label4": "value4"  
}  

For what it's worth, the scores are floats and everything else is a string. The number of returned concepts under "label2" is variable.

I'm attempting to deserialize it using JSON.net. The only content I actually care about is the inside nest of arrays labelled "label2", however the lack of labels inside the arrays is blocking me at every turn.

I've tried a variety of approaches, but the most successful so far seems to be this:

public class Parsed_JSON {
    public string label1 { get; set; }
    public ICollection<Full_Result> label2 { get; set; }
    public string label3 { get; set; }
    public string label4 { get; set; }
}

public class Full_Result {
    public IList<string> values { get; set; }
    public float score { get; set; }
}

Parsed_JSON result = JsonConvert.DeserializeObject<Parsed_JSON>(JSON);

However this is failing with the error:

Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'JSON_Parsing+Full_Result' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.

Ultimately I'll be looking to iterate through the contents of label2 so that I can build a DataTable of them like so:

concept_id_1   concept_1   score_1  
concept_id_2   concept_2   score_2

How can I deserialize this JSON?

Phueal
  • 113
  • 5
  • https://stackoverflow.com/a/48023576/4180382 – Ole EH Dufour Oct 10 '18 at 15:35
  • This: `[ "concept_id_1", "concept_1" ], score_1 ` is not the class **Full_Result** that you have described, it is an array of different types – Markiian Benovskyi Oct 10 '18 at 15:37
  • @MarkiianBenovskyi Thank you, are you able to suggest how I can modify the Parsed_JSON class appropriately? – Phueal Oct 10 '18 at 15:41
  • @OleEHDufour Thank you, that looks really useful, but unfortunately I'm not able to use Visual Studio (long story) – Phueal Oct 10 '18 at 15:42
  • You'll need a custom creation converter: https://www.newtonsoft.com/json/help/html/CustomCreationConverter.htm or https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm – Christoph Lütjen Oct 10 '18 at 15:43
  • 1
    I can suggest you to use dynamic objects for that https://stackoverflow.com/a/9326146/4697963 – Markiian Benovskyi Oct 10 '18 at 15:43
  • You can use your current typed data model if you include `ObjectToArrayConverter` from [this answer](https://stackoverflow.com/a/39462464/3744182) to [C# JSON.NET - Deserialize response that uses an unusual data structure](https://stackoverflow.com/q/39461518/3744182). You'll need to mark the properties of `Full_Result` with `[JsonProperty(Order = N)]` attributes. – dbc Oct 10 '18 at 16:00
  • @MarkiianBenovskyi Thanks, although I didn't use dynamic objects in the end your suggestion did lead me to a working approach. – Phueal Oct 11 '18 at 08:44

1 Answers1

1

You can use the custom JsonConverter ObjectToArrayConverter<Full_Result> from this answer to C# JSON.NET - Deserialize response that uses an unusual data structure to deserialize your JSON into your existing typed data model. Modify Full_Result as follows:

[JsonConverter(typeof(ObjectToArrayConverter<Full_Result>))]
public class Full_Result 
{
    [JsonProperty(Order = 1)]
    public IList<string> values { get; set; }
    [JsonProperty(Order = 2)]
    public float score { get; set; }
}

And you will now be able to deserialize as follows:

Parsed_JSON result = JsonConvert.DeserializeObject<Parsed_JSON>(JSON);

Notes:

  • ObjectToArrayConverter<T> works by mapping the serializable members of T to an array, where the array sequence is defined by the value of the JsonPropertyAttribute.Order attribute applied to each member. Data contract attributes with DataMemberAttribute.Order set could be used instead, if you prefer.

  • In your JSON the "score" values are not actually numbers:

    score_1
    score_2
    

    I am assuming that this is a typo in the question and that these values are in fact well-formed numbers as defined by the JSON standard.

Sample fiddle here.

dbc
  • 104,963
  • 20
  • 228
  • 340