问题
I am trying to convert the below JSON property into an object. The string array is kind of a mixed type: its elements may be strings or string arrays. (Although the string arrays only show up in the occasional record.)
I made the booster
property a List<String>
, which is fine, but the few rows that have the array at the end cause parsing to fail. Any ideas how I could handle this situation?
"booster": [
"land",
"marketing",
"common",
"common",
"common",
"common",
"common",
"common",
"common",
"common",
"common",
"common",
"uncommon",
"uncommon",
"uncommon",
[
"rare",
"mythic rare"
]
]
using(var db = new MTGFlexContext()){
JObject AllData = JsonConvert.DeserializeObject<JObject>(File.ReadAllText(path));
List<String> SetCodes = db.Sets.Select(x => x.Code).ToList();
foreach (var set in AllData)
{
try
{
Set convert = JsonConvert.DeserializeObject<Set>(set.Value.ToString()) as Set;
if (!SetCodes.Contains(set.Key))
{
convert.Name = set.Key;
foreach (var c in convert.Cards)
{
db.Cards.Add(c);
db.SaveChanges();
}
db.Sets.Add(convert);
db.SaveChanges();
}
}
}
}
The full json is 40mb http://mtgjson.com/
回答1:
You could make booster
a List<dynamic>
. It would deserialize correctly and for those indices that are not strings you could cast as JArray and get the values.
class MyObject {
List<dynamic> booster { get; set; }
}
var result = JsonConvert.Deserialize<MyObject>(json);
string value = result.booster[0];
var jArray = result.booster[15] as JArray;
var strings = jArray.Values<string>();
foreach(var item in strings)
Console.WriteLine(item);
UPDATE: Maybe writing a custom json converter can do what you want. This code may be error prone and there's not a lot of error handling or checking. It just demonstrates and illustrates how you can do it:
public class CustomConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException(); // since we don't need to write a serialize a class, i didn't implement it
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jObject = JObject.Load(reader); // load the json string into a JObject
foreach (KeyValuePair<string, JToken> jToken in jObject) // loop through the key-value-pairs
{
if(jToken.Key == "booster") // we have a fixed structure, so just wait for booster property
{
// we take any entry in booster which is an array and select it (in this example: ['myth', 'mythic rare'])
var tokens = from entry in jToken.Value
where entry.Type == JTokenType.Array
select entry;
// let's loop through the array/arrays
foreach (var entry in tokens.ToList())
{
if (entry.Type == JTokenType.Array)
{
// now we take every string of ['myth', 'mythic rare'] and put it into newItems
var newItems = entry.Values<string>().Select(e => new JValue(e));
// add 'myth' and 'mythic rare' after ['myth', 'mythic rare']
// now the json looks like:
// {
// ...
// ['myth', 'mythic rare'],
// 'myth',
// 'mythic rare'
// }
foreach (var newItem in newItems)
entry.AddAfterSelf(newItem);
// remove ['myth', 'mythic rare']
entry.Remove();
}
}
}
}
// return the new target object, which now lets us convert it into List<string>
return new MyObject
{
booster = jObject["booster"].Values<string>().ToList()
};
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(MyObject);
}
}
Hope it helps...
来源:https://stackoverflow.com/questions/29459064/json-net-parsing-mixed-string-and-array