简体   繁体   English

当我不知道键和属性没有名称时,如何在 C# 中解析 JSON 对象?

[英]How do I parse a JSON object in C# when I don't know key and properties don't have names?

Here is my unparsed JSON:这是我未解析的 JSON:

{ "1": [ [ [ 2015, 6, 1, 8, 0, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 1, 9, 30, 0, 3600, "Europe/London", "BST", 1 ] ], [ [ 2015, 6, 1, 8, 30, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 1, 10, 0, 0, 3600, "Europe/London", "BST", 1 ] ], [ [ 2015, 6, 1, 9, 0, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 1, 10, 30, 0, 3600, "Europe/London", "BST", 1 ] ], [ [ 2015, 6, 1, 9, 30, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 1, 11, 0, 0, 3600, "Europe/London", "BST", 1 ] ] ], "2": [ [ [ 2015, 6, 2, 8, 0, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 2, 9, 30, 0, 3600, "Europe/London", "BST", 1 ] ], [ [ 2015, 6, 2, 8, 30, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 2, 10, 0, 0, 3600, "Europe/London", "BST", 1 ] ], [ [ 2015, 6, 2, 9, 0, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 2, 10, 30, 0, 3600, "Europe/London", "BST", 1 ] ], [ [ 2015, 6, 2, 9, 30, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 2, 11, 0, 0, 3600, "Europe/London", "BST", 1 ] ] ], "3": [ { "1": [ [ [ [ 2015, 6, 1, 8, 0, 0, 3600, "欧洲/伦敦", "BST", 1 ], [ 2015, 6, 1, 9, 30, 0, 3600, "欧洲/伦敦", "BST", 1 ] ], [ [ 2015, 6, 1, 8, 30, 0, 3600, "欧洲/伦敦", "BST", 1 ], [ 2015, 6, 1, 10, 0, 0, 3600, "欧洲/伦敦", "BST", 1 ] ], [ [ 2015, 6, 1, 9, 0, 0, 3600, "欧洲/伦敦", "BST", 1 ] , [ 2015, 6, 1, 10, 30, 0, 3600, "欧洲/伦敦", "BST", 1 ] ], [ [ 2015, 6, 1, 9, 30, 0, 3600, "欧洲/伦敦", "BST", 1 ], [ 2015, 6, 1, 11, 0, 0, 3600, "欧洲/伦敦", "BST", 1 ] ] ], "2": [ [ [ 2015, 6, 2, 8, 0, 0, 3600, "欧洲/伦敦", "BST", 1 ], [ 2015, 6, 2, 9, 30, 0, 3600, "欧洲/伦敦", "BST", 1 ] ], [ [ 2015, 6, 2, 8, 30, 0, 3600, "欧洲/伦敦", "BST", 1 ], [ 2015, 6, 2, 10, 0, 0, 3600, "欧洲/伦敦", "BST", 1 ] ], [ [ 2015, 6, 2, 9, 0, 0, 3600, "欧洲/伦敦", "BST", 1 ], [ 2015, 6, 2, 10, 30, 0, 3600, "欧洲/伦敦", "BST", 1 ] ], [ [ 2015, 6, 2, 9, 30, 0, 3600, "欧洲/伦敦", "BST", 1 ], [ 2015, 6, 2, 11, 0, 0, 3600, "Europe/London", "BST", 1 ] ] ], "3": [ [ [ 2015, 6, 3, 8, 0, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 3, 9, 30, 0, 3600, "Europe/London", "BST", 1 ] ], [ [ 2015, 6, 3, 8, 30, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 3, 10, 0, 0, 3600, "Europe/London", "BST", 1 ] ], [ [ 2015, 6, 3, 9, 0, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 3, 10, 30, 0, 3600, "Europe/London", "BST", 1 ] ], [ [ 2015, 6, 3, 9, 30, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 3, 11, 0, 0, 3600, "Europe/London", "BST", 1 ] ] ], "4": [ [ [ 2015, 6, 4, 8, 0, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 4, 9, 30, 0, 3600, "Europe/London", "BST", 1 ] ], [ [ 2015, 6, 4, 8, 30, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 4, 10, 0, 0, 3600, "Europe/London", "BST", 1 ] ], [ [ 2015, 6, 4, 9, 0, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 4, 10, 30, 0, 3600, "Europe/London", "BST", 1 ] ], [ [ 2015, 6, 4, 9, 30, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 4, 11, 0, 0, 3600, "Europe/London", "BST", 1 ] ] ]} [ [ 2015, 6, 3, 8, 0, 0, 3600, "欧洲/伦敦", "BST", 1 ], [ 2015, 6, 3, 9, 30, 0, 3600, "欧洲/伦敦", "BST", 1 ] ], [ [ 2015, 6, 3, 8, 30, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 3, 10, 0, 0, 3600, "欧洲/伦敦", "BST", 1 ] ], [ [ 2015, 6, 3, 9, 0, 0, 3600, "欧洲/伦敦", "BST", 1 ], [ 2015, 6, 3, 10, 30, 0, 3600, "欧洲/伦敦", "BST", 1 ] ], [ [ 2015, 6, 3, 9, 30, 0, 3600, "欧洲/伦敦", "BST", 1 ], [ 2015, 6, 3, 11, 0, 0, 3600, "Europe/London", "BST", 1 ] ] ], "4": [ [ [ 2015, 6, 4, 8, 0, 0, 3600, "欧洲/伦敦", "BST", 1 ], [ 2015, 6, 4, 9, 30, 0, 3600, "欧洲/伦敦", "BST", 1 ] ], [ [ 2015, 6, 4, 8, 30, 0, 3600, "欧洲/伦敦", "BST", 1 ], [ 2015, 6, 4, 10, 0, 0, 3600, "欧洲/伦敦", "BST", 1 ] ], [ [ 2015, 6, 4, 9, 0, 0, 3600, "欧洲/伦敦", "BST", 1 ], [ 2015, 6, 4, 10, 30, 0, 3600, "欧洲/London", "BST", 1 ] ], [ [ 2015, 6, 4, 9, 30, 0, 3600, "Europe/London", "BST", 1 ], [ 2015, 6, 4, 11, 0, 0, 3600, "欧洲/伦敦", "BST", 1 ] ] ]}

This is the basic format:这是基本格式:

ROOT

 Day of the month

      time slot

           time slot start

           time slot end

This is what it looks like formatted:这是格式化后的样子:

JSON 查看器

I cannot figure out for the life of me how to drill through this.我一生都无法弄清楚如何钻通这个。 This question should be similar to How do I parse a JSON object in C# when I don't know the key in advance?这个问题应该类似于How do I parse a JSON object in C# when I don't know the key?

If I do the following, I get "System.InvalidOperationException: Cannot access child value on Newtonsoft.Json.Linq.JValue."如果我执行以下操作,我会收到“System.InvalidOperationException:无法访问 Newtonsoft.Json.Linq.JValue 上的子值”。

        JObject objTimes = JObject.Parse(strJson);

        foreach (var day in objTimes["1"])
        {
            divTimes.InnerHtml += day[0][0][0];
        }

What you can do is to design a class (named, eg, Entry ) to represent the data representing the lowest level of array in the JSON: [ 2015, 6, 3, 9, 30, 0, 3600, "Europe/London", "BST", 1 ] .您可以做的是设计一个类(命名为例如Entry )来表示表示 JSON 中最低级别数组的数据: [ 2015, 6, 3, 9, 30, 0, 3600, "Europe/London", "BST", 1 ] Then create a JsonConverter to load the array values sequentially into the array.然后创建一个JsonConverter将数组值按顺序加载到数组中。 Finally deserialize the outer dictionary and arrays as appropriate:最后根据需要反序列化外部字典和数组:

Here is one possible class to represent the data of a single inner array:这是一个可能的类来表示单个内部数组的数据:

[JsonConverter(typeof(EntryConverter))]
public class Entry
{
    public Entry()
    {
        // You need to determine whether the time numbers in the JSON are in UTC or in the timezone given in the "TimeZone" field.  If
        // Local, change to DateTimeKind.Local
        DateTime = new DateTime(0, DateTimeKind.Utc); 
    }

    public DateTime DateTime { get; set; }
    public int Number { get; set; } // That 3600 thing.  No idea what it's for.
    public string Destination { get; set; }
    public string TimeZone { get; set; }
    // Not all time zone offsets are integers: https://en.wikipedia.org/wiki/UTC%E2%88%9204:30
    public decimal GmtOffset { get; set; }
}

Next, the converter:接下来是转换器:

public class EntryConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(Entry).IsAssignableFrom(objectType);
    }

    void SetField(Entry entry, int index, JValue value)
    {
        switch (index)
        {
            case 0:
                entry.DateTime = new DateTime((int)value, entry.DateTime.Month, entry.DateTime.Day, entry.DateTime.Hour, entry.DateTime.Minute, entry.DateTime.Second, entry.DateTime.Millisecond, entry.DateTime.Kind);
                break;
            case 1:
                entry.DateTime = new DateTime(entry.DateTime.Year, (int)value, entry.DateTime.Day, entry.DateTime.Hour, entry.DateTime.Minute, entry.DateTime.Second, entry.DateTime.Millisecond, entry.DateTime.Kind);
                break;
            case 2:
                entry.DateTime = new DateTime(entry.DateTime.Year, entry.DateTime.Month, (int)value, entry.DateTime.Hour, entry.DateTime.Minute, entry.DateTime.Second, entry.DateTime.Millisecond, entry.DateTime.Kind);
                break;
            case 3:
                entry.DateTime = new DateTime(entry.DateTime.Year, entry.DateTime.Month, entry.DateTime.Day, (int)value, entry.DateTime.Minute, entry.DateTime.Second, entry.DateTime.Millisecond, entry.DateTime.Kind);
                break;
            case 4:
                entry.DateTime = new DateTime(entry.DateTime.Year, entry.DateTime.Month, entry.DateTime.Day, entry.DateTime.Hour, (int)value, entry.DateTime.Second, entry.DateTime.Millisecond, entry.DateTime.Kind);
                break;
            case 5:
                entry.DateTime = new DateTime(entry.DateTime.Year, entry.DateTime.Month, entry.DateTime.Day, entry.DateTime.Hour, entry.DateTime.Minute, (int)value, entry.DateTime.Millisecond, entry.DateTime.Kind);
                break;
            case 6:
                entry.Number = (int)value;
                break;
            case 7:
                entry.Destination = (string)value;
                break;
            case 8:
                entry.TimeZone = (string)value;
                break; 
            case 9:
                entry.GmtOffset = (decimal)value;
                break;
            default:
                throw new IndexOutOfRangeException(index.ToString());
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var array = JArray.Load(reader);
        if (array == null)
            return existingValue;
        var entry = (existingValue as Entry ?? new Entry());
        for (int i = 0; i < array.Count; i++)
        {
            SetField(entry, i, (JValue)array[i]);
        }
        return entry;
    }

    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

And then use it like:然后像这样使用它:

        var root = JsonConvert.DeserializeObject<Dictionary<int, List<List<Entry>>>>(json);
        Debug.WriteLine(JsonConvert.SerializeObject(root, Formatting.Indented));

Here I compressed all the time information into a single DateTime for conciseness, though you might not want to do this.在这里,为了简洁起见,我将所有时间信息压缩到单个DateTime中,尽管您可能不想这样做。 Also, it's unclear whether the time information is in UTC or in local time.此外,尚不清楚时间信息是 UTC 时间还是本地时间。 If local then my use of DateTime.Kind is wrong.如果是本地的,那么我对DateTime.Kind使用是错误的。

You could extend the converter to serialize the fields in the same order if needed.如果需要,您可以扩展转换器以按相同顺序序列化字段。

Here's somewhat loose implementation with JSON.NET.这是 JSON.NET 的一些松散实现。

First the definition classes.首先是定义类。 TimeSlotInfo holds info about DayOfMonth and timeslots available for that Day of month: TimeSlotInfo 保存有关 DayOfMonth 和该月某天可用的时间段的信息:

public class TimeSlotInfo
{
    public int DayOfMonth { get; set; }

    public List<TimeSlotRange> TimeSlots { get; set; }

    public TimeSlotInfo()
    {
        TimeSlots = new List<TimeSlotRange>();
    }
}

public class TimeSlotRange
{
    public TimeSlotItem Start { get; set; }

    public TimeSlotItem End { get; set; }
}

public class TimeSlotItem
{
    public int Year { get; set; }

    public int Month { get; set; }

    public int Day { get; set; }

    public int Hour { get; set; }

    public int Minute { get; set; }

    public int Second { get; set; }

    public int SecondsInHour { get; set; }

    public string TimezoneStr { get; set; }

    public string BST { get; set; }

    public int SomeNum { get; set; }

    public DateTime AsDateTime
    {
        get { return new DateTime(Year, Month, Day, Hour, Minute, Second); }
    }

    public static TimeSlotItem CreateFromJTokenList(List<JToken> tokenList)
    {
        try
        {
            var result = new TimeSlotItem
            {
                Year = tokenList[0].Value<int>(),
                Month = tokenList[1].Value<int>(),
                Day = tokenList[2].Value<int>(),
                Hour = tokenList[3].Value<int>(),
                Minute = tokenList[4].Value<int>(),
                Second = tokenList[5].Value<int>(),
                SecondsInHour = tokenList[6].Value<int>(),
                TimezoneStr = tokenList[7].Value<string>(),
                BST = tokenList[8].Value<string>(),
                SomeNum = tokenList[9].Value<int>()
            };

            return result;
        }
        catch (Exception)
        {
            return null;
        }
    }
}

And then you need a parser to fill those objects:然后你需要一个解析器来填充这些对象:

var timeSlotInfoList = new List<TimeSlotInfo>();

var jsonVal = System.IO.File.ReadAllText(@"C:\test.json"); // Somehow get JSON string into jsonVal. Not neccessarily from file.
var obj = JsonConvert.DeserializeObject(jsonVal) as JObject;
if (obj != null)
{
    var jobj = obj.AsQueryable();
    foreach (JProperty item in jobj)
    {
        try
        {
            var dayOfMonth = Convert.ToInt32(item.Name);

            var timeSlotInfo = new TimeSlotInfo
            {
                DayOfMonth = dayOfMonth
            };
            timeSlotInfoList.Add(timeSlotInfo);

            var timeSlots = item.Value.ToList();
            foreach (var timeSlotPair in timeSlots)
            {
                var timeSlotPairList = timeSlotPair.ToList();
                if (timeSlotPairList.Count != 2)
                    continue;

                var slotItemStart = TimeSlotItem.CreateFromJTokenList(timeSlotPairList[0].ToList());
                var slotItemEnd = TimeSlotItem.CreateFromJTokenList(timeSlotPairList[0].ToList());

                if (slotItemStart != null && slotItemEnd != null)
                {
                    timeSlotInfo.TimeSlots.Add(new TimeSlotRange
                    {
                        Start = slotItemStart,
                        End = slotItemEnd,
                    });
                }
            }

        }
        catch (Exception)
        {
        }
    }
}

At the end timeSlotInfoList contains list of all Days of months and its TimeSlots (with ranges from Start to End).最后timeSlotInfoList包含所有月份的天数及其时间timeSlotInfoList列表(范围从开始到结束)。

This code might need some more tweaking regarding exceptions, validation, etc, but this is some basic idea about parsing such a thing.这段代码可能需要对异常、验证等进行更多调整,但这是解析此类事物的一些基本思想。 If I've made any mistake I'd appreciate some comment about it.如果我犯了任何错误,我将不胜感激。 Anyway, hope it helps.无论如何,希望它有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 当我事先不知道密钥时,如何在 C# 中解析 JSON 对象? - How do I parse a JSON object in C# when I don't know the key in advance? 当我不知道 Java 类在哪个包中时,如何找到它的包名? - How do I find package names for java classes when I don't know what package it's in? 如何比较两个 IEnumerable<T> 在 C# 中,如果我不知道实际的对象类型? - How to compare two IEnumerable<T> in C# if I don't know the actual object type? 如果我不知道GUID,如何使用c#在Microsoft CRM上检索一条记录? - How do I retrieve a single record on Microsoft CRM using c# if I don't know the GUID? 如何反序列化没有名称的JSON.NET对象? - How do I deserialize JSON.NET objects that don't have names? 如果我不知道c#中的结构,如何访问对象的内容? - How to access contents of Object If I don't know the structure in c#? 我不知道如何使用 C# ASP.NET 进行 Soap 请求 - I don't know how to do a Soap Request using C# ASP.NET 当我不知道原始编码时,如何在 c# 中将文件转换为 unix 或 windows - How to convert file to unix or windows in c# when I don't know the original encoding 我在调试时遇到问题,我不知道 C# 的原因是什么 - i have an issue in debugging and i don't know whats is the reason C# 我需要做一个 python 项目,但我知道 C# 并且不知道如何转换它 - I need to make a python project but I know C# and don't know how to convert it
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM