1

I have a json file which has either of the following formats:

  1. Sample 1:
{
  "MyOrders": [
    {
      "order": "my order1",
      "url": "tt"
    }
  ]
}

Sample 2:

{
  "MyOrders": [
    [
      {
        "order": "my order 1",
        "url": "ddfdfd"
      },
      {
        "order": "order 2",
        "url": "asdfwe"
      }
     ],
     [
      {
        "order": "my order 3",
        "url": "ertrt"
      },
      {
        "order": "my order 4",
        "url": "werwe"
      }
    ]
  ]
}

I have the following code:

InputItems root = JsonConvert.DeserializeObject<InputItems>(myJsonText);

And I have the following classes:

public class InputItems 
    {
            [JsonProperty("MyOrders")]
            public List<Order> objects { get; set; }
        
    }

    public class Order
    {

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

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

}

But it works just for the first case. How can I improve it to also cover the second sample format?

Thanks in advance.

aturan23
  • 4,798
  • 4
  • 28
  • 52
user13578
  • 107
  • 9
  • You don't have to quote your JSON (the > prefix) by the way – ProgrammingLlama Sep 18 '20 at 10:42
  • 3
    If you look closely at your "sample 2" JSON, you'll note that you don't have an array of orders - you have an array or arrays of orders. Therefore in .NET that would be a List of List of Order, not just a List of Order. As for how to deserialize both of them with the same code, I'd probably create a `JsonConverter` to apply to `List` and then have it work out if the `JToken` is a `JObject` or `JArray` and deserialize accordingly. I'll help later if i have time. – ProgrammingLlama Sep 18 '20 at 10:43
  • Can be helpful: https://stackoverflow.com/questions/18994685/how-to-handle-both-a-single-item-and-an-array-for-the-same-property-using-json-n – apocalypse Sep 18 '20 at 11:28

1 Answers1

2

I've written a converter that should help you:

public class SingleArrayOrNestedConverter<TItemType> : JsonConverter<List<TItemType>>
{
    public override List<TItemType> ReadJson(JsonReader reader, Type objectType, List<TItemType> existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        // Read the object as JSON
        var token = JToken.ReadFrom(reader);
        if (token is JObject) // it's just a lone object, so wrap it in a list and return it
        {
            return new List<TItemType>() { token.ToObject<TItemType>(serializer) };
        }
        else if (token is JArray arrayOfObjects) // it's an array of objects, so let's loop through
        {
            var result = new List<TItemType>();
            foreach (var item in arrayOfObjects)
            {
                if (item is JObject) // the nested item is an object, so let's add it to the list
                {
                    result.Add(item.ToObject<TItemType>(serializer));
                }
                else if (item is JArray nestedArrayOfObjects) // the nested item is an array, so let's loop through it
                {
                    foreach (var nestedItem in nestedArrayOfObjects)
                    {
                        // this will throw an exception if nestedItem doesn't represent an object
                        result.Add(nestedItem.ToObject<TItemType>(serializer));
                    }
                }
            }
            return result;
        }
        return null;
    }

    // we can't use this code for serializing so make sure JSON.NET doesn't try
    public override bool CanWrite => false;

    public override void WriteJson(JsonWriter writer, List<TItemType> value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

This will work with the following JSON samples.

Sample 1:

{
    "MyOrders": [{
            "order": "my order1",
            "url": "tt"
        }
    ]
}

Sample 2:

{
    "MyOrders": [
        [{
                "order": "my order1",
                "url": "tt"
            }
        ]]
}

Sample 3:

{
    "MyOrders": {
        "order": "my order1",
        "url": "tt"
    }
}

Sample 4:

{
    "MyOrders": [
        [{
                "order": "my order1",
                "url": "tt"
            }
        ], {
            "order": "my order1",
            "url": "tt"
        }
    ]
}

To apply it to your code, you'll need to use the JsonConverterAttribute:

[JsonConverter(typeof(SingleArrayOrNestedConverter<Order>))]

Which looks like this:

public class InputItems
{
    [JsonProperty("MyOrders")]
    [JsonConverter(typeof(SingleArrayOrNestedConverter<Order>))]
    public List<Order> objects { get; set; }
}
Dharman
  • 30,962
  • 25
  • 85
  • 135
ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86