【问题标题】:How to get the value by a key from a super nested Json如何从超级嵌套的 Json 中通过键获取值
【发布时间】:2019-09-25 12:57:59
【问题描述】:
"_embedded": {
"cscaia:status_report": {
  "_links": {
    "self": {
      "title": "status_report",
      "name": "status_report",
      "href": "https://api.dxc-dev-aia.hub-1.dev.us.insurance.dxc.com/quotes/ID-mrMxY1Dg/status_report"
    },
    "type": {
      "href": "https://diaas-dev.gtaia-test-domain.net/std-dev-lux-13100/insurance/schemas/quotes/statusReportDocument"
    },
    "up": {
      "href": "https://api.dxc-dev-aia.hub-1.dev.us.insurance.dxc.com/quotes/ID-mrMxY1Dg"
    }
  },
  "consistent": false,
  "messages": [
    {
      "message": "Incomplete attribute",
      "context": [
        {
          "propertyNames": [
            "quote$distributor_id"
          ]
        }
      ],
      "severity": "error",
      "code": "incomplete_attr"
    }
  ]
}

}

在这里我需要找出键“严重性”的值,但我不知道它的级别。我没有它的父级的键以及它嵌套在其中的键,因为 json 将始终是动态的。

我尝试过使用扩展方法。但是对于嵌套键,我没有得到结果。

public static TType JsonValue<TType>(this JObject obj, string key)
    {
        object result = null; //default to null if nothing is found

        foreach (var item in obj)
        {
            var token = item;

            if (token.Key.Equals(key, StringComparison.InvariantCultureIgnoreCase))
            {
                result = token.Value.ToObject<TType>(); //return the value found
                break;
            }

            if (!obj[token.Key].Children().Any())
                continue;

            var jt = obj[token.Key].ToString();

            if (!jt.StartsWith("["))
            {
                result = JsonValue<TType>(JObject.Parse(jt), key);
            }
            else
            {
                obj[token.Key].Children().ToList().ForEach(x =>
                {
                    //only the first match will be returned
                    result = JsonValue<TType>(JObject.Parse(x.ToString()), key);
                });
            }

            if (result != null)
                break;
        }
        return (TType)result;
    }

【问题讨论】:

  • 你要做的是在 JS 或 C# 中都是相反的
  • 我在 c# 中试过,但如果你能在 js 中给出解决方案也很好。@user7417866

标签: javascript c# json linq


【解决方案1】:

如果找到值,您可以采用递归方法并返回。

function getValue(object, key) {
    var value;

    if (!object || typeof object !== 'object') return;
    if (key in object) return object[key];

    Object.values(object).some(v => {
        value = getValue(v, key)
        return value !== undefined;
    });    

    return value;
}

var data = { _embedded: { "cscaia:status_report": { _links: { self: { title: "status_report", name: "status_report", href: "https://api.dxc-dev-aia.hub-1.dev.us.insurance.dxc.com/quotes/ID-mrMxY1Dg/status_report" }, type: { href: "https://diaas-dev.gtaia-test-domain.net/std-dev-lux-13100/insurance/schemas/quotes/statusReportDocument" }, up: { href: "https://api.dxc-dev-aia.hub-1.dev.us.insurance.dxc.com/quotes/ID-mrMxY1Dg" } }, consistent: false, messages: [{ message: "Incomplete attribute", context: [{ propertyNames: ["quote$distributor_id"] }], severity: "error", code: "incomplete_attr" }] } } };

console.log(getValue(data, 'severity'));
console.log(getValue(data, 'href'));

【讨论】:

    【解决方案2】:

    只需使用递归函数即可遍历所有级别。

    var _embedded = {
      "cscaia:status_report": {
        "_links": {
          "self": {
            "title": "status_report",
            "name": "status_report",
            "href": "https://api.dxc-dev-aia.hub-1.dev.us.insurance.dxc.com/quotes/ID-mrMxY1Dg/status_report"
          },
          "type": {
            "href": "https://diaas-dev.gtaia-test-domain.net/std-dev-lux-13100/insurance/schemas/quotes/statusReportDocument"
          },
          "up": {
            "href": "https://api.dxc-dev-aia.hub-1.dev.us.insurance.dxc.com/quotes/ID-mrMxY1Dg"
          }
        },
        "consistent": false,
        "messages": [
          {
            "message": "Incomplete attribute",
            "context": [
              {
                "propertyNames": [
                  "quote$distributor_id"
                ]
              }
            ],
            "severity": "error",
            "code": "incomplete_attr"
          }
        ]
      }
    }
    
    function recursive_search (object) {
    
      let output = null;
    
      //check if object is an array or object
      if (Array.isArray (object)) {
      
        //check every array-element recursive
        for (let i in object)
          output = recursive_search (object[i])
    
      } else
      if (typeof object === 'object') {
      
        //get all keys of object
        let keys = Object.keys (object);
        
        //check every key if it is 'serverity'. if not check every property recursive 
        for (let i in keys)
          if (keys[i] === 'severity') {
          
            output = object[keys[i]];
            break;
          
          } else
          if (typeof object === 'object')
            output = recursive_search (object[keys[i]])
      
      }
      
      return output;
    
    }
    
    //get serverity
    serverity = recursive_search (_embedded)
    
    console.log ('serverity = ' + serverity);

    【讨论】:

      【解决方案3】:

      假设您想使用 C# 实现此目的,您可以尝试使用 Newtonsoft.Json.Linq 查询所有后代,直到找到正确的属性。

      这应该可以工作 (demo):

      public static T GetJsonPropertyValue<T>(string json, string property)
      {
          var parsedJson = JObject.Parse(json);
          var token = parsedJson.Descendants()
              .FirstOrDefault(t => t.Type == JTokenType.Property
                  && ((JProperty)t).Name == property);
          return token is JProperty
              ? token.First().Value<T>()
              : token.Value<T>();
      }
      

      从你的例子:

      static void Main(string[] args)
      {
          var json = @"{
           ""_embedded"": {
              ""cscaia:status_report"": {
                  ""_links"": {
                      ""self"": {
                          ""title"": ""status_report"",
                          ""name"": ""status_report"",
                          ""href"": ""https://api.dxc-dev-aia.hub-1.dev.us.insurance.dxc.com/quotes/ID-mrMxY1Dg/status_report""
                      },
                      ""type"": {
                          ""href"": ""https://diaas-dev.gtaia-test-domain.net/std-dev-lux-13100/insurance/schemas/quotes/statusReportDocument""
                      },
                      ""up"": {
                          ""href"": ""https://api.dxc-dev-aia.hub-1.dev.us.insurance.dxc.com/quotes/ID-mrMxY1Dg""
                      }
                  },
                  ""consistent"": false,
                  ""messages"": [
                      {
                          ""message"": ""Incomplete attribute"",
                          ""context"": [
                              {
                                  ""propertyNames"": [
                                      ""quote$distributor_id""
                                  ]
                              }
                          ],
                          ""severity"": ""error"",
                          ""code"": ""incomplete_attr""
                      }
                  ]
              }
          }
      }";
          var context = GetJsonPropertyValue<dynamic>(json, "context");
          var severity = GetJsonPropertyValue<string>(json, "severity");
          Console.WriteLine(severity);
          Console.WriteLine(context);
          Console.ReadKey();
      }
      

      【讨论】:

      • 收到一个错误,指出无法将 Newtonsoft.Json.Linq.JObject 转换为 Newtonsoft.Json.Linq.JToken。
      • 所以你有一个带有嵌套对象的严重性属性?假设它是一个简单的键字符串值属性,就像您的示例一样,它可以工作。最终发布给你错误的 Json。
      • 请找到我面临问题的 json 的链接。xfl.jp/tvBEai
      • 我不确定您调整了什么,但上述方法适用于您的 json 文件。这是demonstration
      • 使用关键字 postal_address$address_category 并尝试抛出异常。
      猜你喜欢
      • 2016-08-19
      • 1970-01-01
      • 2019-08-20
      • 2022-10-16
      • 1970-01-01
      • 1970-01-01
      • 2019-12-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多