【问题标题】:json.net parsing mixed string and arrayjson.net 解析混合字符串和数组
【发布时间】:2015-04-05 15:46:28
【问题描述】:

我正在尝试将以下 JSON 属性转换为对象。字符串数组是一种混合类型:它的元素可以是字符串或字符串数​​组。 (虽然字符串数组只是偶尔出现在记录中。)

我将booster 属性设为List<String>,这很好,但是最后包含数组的几行会导致解析失败。任何想法我可以如何处理这种情况?

  "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();
            }
        }
    }
}

完整的 json 为 40mb http://mtgjson.com/

【问题讨论】:

  • 您对对象格式有多少控制权?如果数组只出现在最后,你能把它分解成包含对象的一个​​单独的属性吗?

标签: c# parsing json.net


【解决方案1】:

您可以将booster 设为List&lt;dynamic&gt;。它会正确反序列化,对于那些不是字符串的索引,您可以将其转换为 JArray 并获取值。

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); 

更新:也许写一个自定义的 json 转换器可以做你想做的事。此代码可能容易出错,并且没有太多的错误处理或检查。它只是演示和说明如何做到这一点:

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);
    }
}

希望对你有帮助...

【讨论】:

  • 谢谢,斯特凡。好主意,但我正在使用实体框架将 json 导入 sql 服务器,不要认为它会喜欢那样 ;) 有没有办法在解析该字段时获取回调,以便我做出反应?我只是使用最基本的方法 atm 并且担心我需要更深入一点:/
  • @fruitbatinshades 你真的只是想“等待”数组的到来(并将它们插入数据库)还是想反序列化没有数组的对象?
  • 此时我希望能够忽略数组部分或将其作为两个额外的字符串使用,而不是 json.net 错误。 [JsonProperty("booster")] public string[] Booster { get;放; }
猜你喜欢
  • 2017-01-27
  • 2011-09-08
  • 1970-01-01
  • 1970-01-01
  • 2015-02-15
  • 2019-12-11
  • 1970-01-01
  • 2017-08-31
  • 2010-09-20
相关资源
最近更新 更多