简体   繁体   English

使用表示查询的未知数量的嵌套数组反序列化JSON

[英]Deserializing JSON with an unknown number of nested arrays representing a query

I have some JSON as shown below. 我有一些JSON,如下所示。

{
  "queryEntry": [
    [
      {
        "type": "expression",
        "key": "Account.Name",
        "operators": "=",
        "value": "asd"
      }
    ],
    {
      "type": "conjunction",
      "value": "OR",
      "key": null,
      "operators": null
    },
    [
      {
        "type": "expression",
        "key": "Account.TotalEmployees",
        "operators": "=",
        "value": "123"
      },
      {
        "type": "conjunction",
        "value": "AND",
        "key": null,
        "operators": null
      },
      [
        {
          "type": "expression",
          "key": "Account.LastYearRevenue",
          "operators": "=",
          "value": "123"
        },
        {
          "type": "conjunction",
          "value": "OR",
          "key": null,
          "operators": null
        },
        [
          {
            "type": "expression",
            "key": "Account.Last5YearRevenue",
            "operators": "=",
            "value": "123"
          }
        ]
      ]
    ],
    {
      "type": "conjunction",
      "value": "AND",
      "key": null,
      "operators": null
    },
    [
      {
        "type": "expression",
        "key": "Account.OwnerName",
        "operators": "=",
        "value": "asd"
      }
    ]
  ]
}

This is actually a where condition in SQL which we are generating from jQuery. 这实际上是我们从jQuery生成的SQL中的where条件。 I have to deserialize this string to a class in C#. 我必须将此字符串反序列化为C#中的类。

Could anyone guide me as to what class I should create in order to deserialize this? 任何人都可以指导我为什么要创建这个类来反序列化这个? Also, it is unknown how deep the nested array goes. 此外,不知道嵌套数组有多深。

This is a difficult JSON format to work with, because it is a recursive array structure where the arrays can contain either objects or arrays or a combination of both. 这是一种难以使用的JSON格式,因为它是一种递归数组结构,其中数组可以包含对象或数组或两者的组合。 I can see that the JSON objects represent pieces of a query, but the query subexpressions are not within the objects like I would expect. 我可以看到JSON对象表示查询的各个部分,但查询子表达式不在我想要的对象内。 Rather, it seems like the arrays are being used as literal parenthesis for grouping the query! 相反,似乎数组被用作文字括号来分组查询!

I think the best way to get this to deserialize into a halfway sane class structure is to use the Composite pattern , where one class represents both a single piece of the query (ie expression or conjunction) and also a grouping of the same. 我认为将其反序列化为中间合理类结构的最佳方法是使用Composite模式 ,其中一个类既代表查询的单个部分(即表达式或连接),也表示相同的分组。 Something like this: 像这样的东西:

class QueryEntry
{
    public string Type { get; set; }
    public string Key { get; set; }
    public string Operators { get; set; }
    public string Value { get; set; }
    public List<QueryEntry> Group { get; private set; }
    public bool IsGroup { get { return Group.Count > 0; } }

    public QueryEntry()
    {
        Group = new List<QueryEntry>();
    }
}

We also need a wrapper class to handle the queryEntry property at the root of the JSON: 我们还需要一个包装类来处理JSON根目录下的queryEntry属性:

class RootObject
{
    public QueryEntry QueryEntry { get; set; }
}

Now, since the JSON could be an object or a heterogeneous array at any level, we can't just throw this class at Json.Net and expect it to deserialize properly out of the gate. 现在,既然JSON可以是任何级别的对象或异构数组,我们不能只在Json.Net上抛出这个类,并期望它在门外正确地反序列化。 (You are using Json.Net aren't you? Your question did not say.) We will need to use a custom JsonConverter to translate the JSON structure into the composite class structure: (您正在使用Json.Net ?你不是你的问题没有说)。我们将需要使用自定义JsonConverter到JSON结构翻译成复合类结构:

class QueryEntryConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(QueryEntry);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        QueryEntry entry = new QueryEntry();
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Object)
        {
            serializer.Populate(token.CreateReader(), entry);
        }
        else if (token.Type == JTokenType.Array)
        {
            foreach (JToken child in token)
            {
                entry.Group.Add(child.ToObject<QueryEntry>(serializer));
            }
        }
        return entry;
    }

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

To deserialize, we can pass an instance of the converter to DeserializeObject<T> like this: 要反序列化,我们可以将转换DeserializeObject<T>的实例传递给DeserializeObject<T>如下所示:

var root = JsonConvert.DeserializeObject<RootObject>(json, new QueryEntryConverter());

Finally, if we want to convert the deserialized query expression tree into a readable string, we will need a recursive ToString() method on the QueryEntry class: 最后,如果我们想将反序列化的查询表达式树转换为可读的字符串,我们需要在QueryEntry类上使用递归的ToString()方法:

    public override string ToString()
    {
        if (IsGroup)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append('(');
            foreach (QueryEntry entry in Group)
            {
                sb.Append(entry.ToString());
            }
            sb.Append(')');
            return sb.ToString();
        }
        else if (Type == "expression")
        {
            return Key + ' ' + Operators + ' ' + Value;
        }
        else if (Type == "conjunction")
        {
            return ' ' + Value + ' ';
        }
        return string.Empty;
    }

Then we can do: 然后我们可以这样做:

Console.WriteLine(root.QueryEntry.ToString());

With the JSON in your question, the output would be: 在您的问题中使用JSON,输出将是:

((Account.Name = asd) OR (Account.TotalEmployees = 123 AND (Account.LastYearRevenue = 123 OR (Account.Last5YearRevenue = 123))) AND (Account.OwnerName = asd)) ((Account.Name = asd)OR(Account.TotalEmployees = 123 AND(Account.LastYearRevenue = 123 OR(Account.Last5YearRevenue = 123)))AND(Account.OwnerName = asd))

Here is a working demo: https://dotnetfiddle.net/D3eu5J 这是一个有效的演示: https//dotnetfiddle.net/D3eu5J

you can covert using JsonConvert as follows 您可以使用JsonConvert进行隐蔽,如下所示

MyData tmp = JsonConvert.DeserializeObject<MyData>(json);
foreach (string typeStr in tmp.type[0])
{
    // Do something with typeStr
}

may be create the classs in the properties as fields if you want you use [jsonproperty] annotation for the class properties 如果您希望对类属性使用[jsonproperty]注释,则可以在属性中将类创建为字段

class MyData
{
  @JsonProperty("t")

public string t; 公共字符串t; public bool a; 公共布尔

}

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM