Ajaco
Ajaco

Reputation: 369

Deserialize string-array containing another array

Okay, so I'm working on creating a REST-API, and in order to seed my database I use existing data in the forms of huge JSON-files. And I have a problem when it comes to deserializing one of the fields.

So the JSON looks like this:

{
  "name" : "Magic 2013",
  "booster" : [ 
    "land",
    "marketing",
    "common",
    "common",
    "common",
    "common",
    "common",
    "common",
    "common",
    "common",
    "common",
    "common",
    "uncommon",
    "uncommon",
    "uncommon",
    [
      "rare",
      "mythic rare"
    ]
  ]
}

And when you look at this, you can probably identify the problem as well. There's a field called booster, which is an array of strings.. but the last element is not a string. It's another array. So trying to deserialize it to a string[]-field fails.

I have to work with this format - there's no way for me to change it, so I'm going to have to figure out a smart way to solve this problem. Which is what I need help with.

Are there any way with JSON.NET that i could actually deserialize this? Some way I could do some sort of manual mapping saying that whenever I reach the inner array, I'm going to do some custom code?

I would be grateful for any help!

Thanks!

Upvotes: 1

Views: 80

Answers (3)

Darin Dimitrov
Darin Dimitrov

Reputation: 1039140

You could define the booster property as JArray:

public JArray Booster { get; set; }

This doesn't enforce a specific data type of the array. You can then loop through each element of this array (which will be a JToken) and test if it is a string value or yet another JArray and act accordingly:

foreach (JToken token in model.Booster)
{
    var array = token as JArray();
    if (array != null)
    {
        // The element is an array, so you can process its subelements here
    }
    else
    {
        // It's probably a string element
        string value = token.ToObject<string>();
    }
}

Upvotes: 3

Shashank Shekhar
Shashank Shekhar

Reputation: 4178

If it will always be the last element that will have the array instead of a string, you can deserializer is using

public class RootObject
{
    public string name { get; set; }
    public List<object> booster { get; set; }
}

and then extract element of the booster List using

var oddItem = booster[booster.Count -1];

This is assuming that its always the last element which is an array

Upvotes: 0

Bas
Bas

Reputation: 27105

So this works for me:

class WhateverMyThingIsNamed
{
    public string Name { get; set; }

    public object[] Booster { get; set; }

    public IEnumerable<string> GetBooster()
    {
        foreach (var o in Booster)
        {
            if (o is string)
            {
                yield return (string) o;
            }
            else if (o is JArray)
            {
                foreach (var element in (JArray) o)
                {
                    yield return element.Value<string>();
                }
            }
            else
            {
                throw new InvalidOperationException("Unexpected element");
            }
        }
    } 
}

...

var json = File.ReadAllText("json1.json");
var data = new JsonSerializer().Deserialize<WhateverMyThingIsNamed>(new JsonTextReader(new StringReader(json)));
var boosterList = data.GetBooster().ToList();

Upvotes: 0

Related Questions