无法读取嵌套结构

时间:2020-01-06 17:44:27

标签: c# json unity3d

我正在尝试使用Unity的JSON实用程序读取JSON文件,该文件如下所示:

{ "entries": [{
    "2019": [{
        "january": [{
            "6": [{
                "name": "Litago",
                "ingredients": [{
                    "kaloriar": "20",
                    "salt": "10"
                }]
            }]
        }]
    }]
}]
}

我在如何设置嵌套类方面苦苦挣扎。我目前正在执行此操作,但无法正常工作。

[System.Serializable]
public class Entries
{
    public KeyValuePair<string, List<Year>> Year;
}

[System.Serializable]
public class Year
{
    public KeyValuePair<string, List<Month>> Month;
}

[System.Serializable]
public class Month
{
    public KeyValuePair<string, List<Day>> Day;
}

[System.Serializable]
public class Day
{
    public KeyValuePair<string, List<Meal>> Meal;
}

[System.Serializable]
public class Meal
{
    public string Name;
    public List<KeyValuePair<string, string>> ingredients;
}

我这样读取JSON:

Entries entries = JsonUtility.FromJson<Entries>(JSONString);

理想情况下,我想执行以下操作:

Debug.Log(entries["2019"]["January"]["6"]["name"]); // Should print "Litago"

但是由于我的班级很可能没有正确设置,所以我遇到类型错误。任何想法将不胜感激,并欢迎其他更好的插件阅读JSON的建议!

2 个答案:

答案 0 :(得分:1)

要回答有关如何访问数据的问题,只需执行以下操作即可访问所需的内容。

workout_id

输出

workout_exercises

创建字典词典...

您可以创建一个递归方法来构建您的 JObject entries = JObject.Parse(jsonString); Console.WriteLine(entries["entries"][0]["2019"][0]["january"][0]["6"][0]["ingredients"][0]["kaloriar"].ToString()); 项目。之所以必须是对象字典,是因为每次进入子节点都具有动态值。

20

主要用途

Dictionary<string, object>

结果字典

    public static Dictionary<string, object> BuildDictionary(JObject input)
    {
        var properties = input.Properties();

        // Terminator
        if (properties.ToList().Where(x => x.Name.Equals("name")).Count() > 0)
        {
            Day thisDay = new Day()
            {
                name = input["name"].ToString(),
                ingredients = new Ingredients()
                {
                    kaloriar = input["ingredients"][0]["kaloriar"].ToString(),
                    salt = input["ingredients"][0]["salt"].ToString()
                }
            };
            return new Dictionary<string, object>() { { "Meal", thisDay } };
        }

        // Recursive
        Dictionary<string, object> obj = new Dictionary<string, object>();
        foreach (JProperty property in properties) 
        {
            foreach (var element in input[property.Name])
                obj.Add(property.Name, BuildDictionary(element as JObject));

        }
        return obj;
    }

您可以访问所需的数据,与查找所需的数据非常相似。

   JObject entries = JObject.Parse(jsonString);
   Dictionary<string, object> dict = BuildDictionary(entries);

输出

{
  "entries": {
    "2019": {
      "january": {
        "6": {
          "Meal": {
            "name": "Litago",
            "ingredients": {
              "kaloriar": "20",
              "salt": "10"
            }
          }
        }
      }
    }
  }
}

本质上,您正在做的是获取元素数组并将仅元素转换为字典以访问所需的方式。

答案 1 :(得分:1)

如果您愿意恢复到Json.Net库,则可以利用它的可扩展性点来构建与所需结构非常相似的东西:

  1. []上覆盖List<T>运算符,以便允许字符串输入并使链接看起来更自然。

  2. 覆盖Json.Net附带的ExpandoObjectConverter,因此它将注入您的自定义列表,而不是默认列表。

总体代码可能看起来像这样:

public class SearchableList<T> : List<T>
{
    public object this[string item]
    {
        get { 
            var listItem = this.Cast<IDictionary<string, object>>().First(l => l.ContainsKey(item)); // I am assuming that your top level array items will only have one matching key
            return listItem[item];
        }
    }
}
public class MyConverter : ExpandoObjectConverter
{
    static bool IsPrimitiveToken(JsonToken token)
    {
        if ((uint)(token - 7) <= 5u || (uint)(token - 16) <= 1u)
        {
            return true;
        }
        return false;
    }

    bool MoveToContent(JsonReader reader)
    {
        JsonToken tokenType = reader.TokenType;
        while (tokenType == JsonToken.None || tokenType == JsonToken.Comment)
        {
            if (!reader.Read())
            {
                return false;
            }
            tokenType = reader.TokenType;
        }
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return ReadValue(reader);
    }

    private object ReadValue(JsonReader reader)
    {
        if (!MoveToContent(reader))
        {
            throw new JsonSerializationException("Unexpected end when reading ExpandoObject.");
        }
        switch (reader.TokenType)
        {
            case JsonToken.StartObject:
                return ReadObject(reader);
            case JsonToken.StartArray:
                return ReadList(reader);
            default:
                if (IsPrimitiveToken(reader.TokenType))
                {
                    return reader.Value;
                }
                throw new JsonSerializationException("Unexpected token when converting ExpandoObject");
        }
    }

    private object ReadList(JsonReader reader)
    {
        IList<object> list = new SearchableList<object>(); // it is quite unfortunate to have to reimplement all class just because of this one line.
        while (reader.Read())
        {
            switch (reader.TokenType)
            {
                case JsonToken.EndArray:
                    return list;
                case JsonToken.Comment:
                    continue;
            }
            object item = ReadValue(reader);
            list.Add(item);
        }
        throw new JsonSerializationException("Unexpected end when reading ExpandoObject.");
    }

    private object ReadObject(JsonReader reader)
    {
        IDictionary<string, object> dictionary = new ExpandoObject();
        while (reader.Read())
        {
            switch (reader.TokenType)
            {
                case JsonToken.PropertyName:
                    {
                        string key = reader.Value.ToString();
                        if (!reader.Read())
                        {
                            throw new JsonSerializationException("Unexpected end when reading ExpandoObject.");
                        }                       
                        object obj2 = dictionary[key] = ReadValue(reader);
                        break;
                    }
                case JsonToken.EndObject:
                    return dictionary;
            }
        }
        throw new JsonSerializationException("Unexpected end when reading ExpandoObject.");
    }
}
void Main()
{
    var myConverter = new MyConverter();
    dynamic entries = JsonConvert.DeserializeObject<ExpandoObject>("your json here", myConverter);
    Console.WriteLine(entries.entries["2019"]["january"]["6"]["name"]);
}

您会注意到,MyConverter有很多看似无关的代码,这对于ExpandoObjectConverter开箱即用的可扩展性是非常不幸的。您可能只用股票标准ExpandoObjectConverter来做,但是给定您的源json格式,它产生的对象在遍历时会有些尴尬。

希望这为您提供了探索的途径。

相关问题