【问题标题】:Find pattern in json with json.net and linq使用 json.net 和 linq 在 json 中查找模式
【发布时间】:2017-02-02 15:17:57
【问题描述】:

我正在搜索一个 json 文件,其结构如下:

{
    "objects": [
        {    
        "name": "obj1",
            "state": {
                "type": 4,
                    "childs": [
                         "state": {
                              "type": 5,
                               ...

状态可以包含状态作为子状态,直到任意数量的级别。现在我试图找到包含某种状态模式的所有对象,例如状态 4 与子状态 5 与子状态 2。

到目前为止,我的代码是这样的。

        JObject o = JObject.Parse(System.IO.File.ReadAllText(@"j.json"));

        var oObjects=
            from p in o["objects"]
            where (string)p["state"] == "4"
            select (string)p["name"];

如何扩展代码以查找包含任何级别上的搜索模式的所有对象?

【问题讨论】:

标签: c# json linq json.net


【解决方案1】:

要使其适用于不定级别,则需要使用如下递归方法:

void Main()
{
    var str = @"{
        ""objects"": [
            {
                ""name"": ""obj1"",
                ""state"": {
                    ""type"": 4,
                    ""childs"": [
                        {
                            ""state"": {
                                ""type"": 5
                            }
                        }
                    ]
                }
            }
        ]
    }";

    var obj = JObject.Parse(str);

    GetValidObjects(obj, new string[] { "4", "5" }); // Name list of valid objects
}

而辅助方法定义如下:

public IEnumerable<string> GetValidObjects(JObject obj, IEnumerable<string> values)
{
    return obj["objects"]
        .Where(i => (string)i["state"]["type"] == values.First() && ContainsState((JArray)i["state"]["childs"], values.Skip(1)))
        .Select(i => (string)i["name"]);
}

public bool ContainsState(JArray childs, IEnumerable<string> values)
{
    if (childs == null)
    {
        return values.Count() == 0;
    }

    return childs.Any(i => (string)i["state"]["type"] == values.First() && ContainsState((JArray)i["state"]["childs"], values.Skip(1)));
}

【讨论】:

    【解决方案2】:

    可以选择将 json 转换为 xml,然后使用 xpath 查询来获取节点列表。

            string json = System.IO.File.ReadAllText(@"j.json");
            XmlDocument document = (XmlDocument)JsonConvert.DeserializeXmlNode(json);
            XmlNodeList nodes = document.SelectNodes("//name[../state[type[.=4] and childs/state[type[.=5] and childs/state[type[.=2]]]]]");
    

    【讨论】:

      【解决方案3】:

      您可以为此使用SelectTokens

      var objects = o.SelectTokens("$.objects[?(@.state.type == 4 
                             && @.state.childs[*].state.type == 5)].name")
                          .Select(s => (string)s)
                          .ToList();
      

      【讨论】:

      • 很高兴知道这个辅助方法,但它不适用于 2 以外的其他级别。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-07
      • 1970-01-01
      • 2022-12-13
      • 2023-03-24
      • 1970-01-01
      • 2015-08-28
      相关资源
      最近更新 更多