Ruby,解析一组值的JSON响应

时间:2016-06-08 20:07:37

标签: ruby json

我是红宝石的新手所以请原谅我可能承受的任何无知。我想知道如何解析属于特定键的每个值的JSON响应。响应的格式为

def "domestic rules"(from, to, oneWay, check) {

    expect:
    String mealResponse = getMealResponse(new BookingOptions.BookingOptionsBuilder().setFrom(from).setTo(to).setOneWay(oneWay).build());
    check(mealResponse)

    where:
    from  | to    | oneWay || check
    'MNL' | 'PEK' | true   || assertNoMeals()
}

def assertNoMeals = {
    assert JsonAssert.with(it)
            .assertThat('$.links', hasSize(1))
            .assertThat('$.links[0].rel', is("http://localhost:9001/api/docs/rels/ink/meal-allocations"))
            .assertThat('$.links[0].uri', startsWith("http://localhost:9001/api/tenants/acme/meals/allocations/"));
}

响应中还有其他一些条目,但为了没有大量的代码,我已经缩短了它。我写的代码是:

[
  {
    "id": 10008,
    "name": "vpop-fms-inventory-ws-client",
    "msr": [
      {
        "key": "blocker_violations",
        "val": 0,
        "frmt_val": "0"
      },
    ]
  },
  {
    "id": 10422,
    "name": "websample Maven Webapp",
    "msr": [
      {
        "key": "blocker_violations",
        "val": 0,
        "frmt_val": "0"
      }...

我基本上在寻找每个阻止程序违规的val(json响应包含数百个条目,所以我期待数百个阻止值)。我曾希望num会包含所有&val; s的数组。如果您对此有任何见解,那将会有很大的帮助!

EDIT!我正在获得

的控制台输出
require 'uri'
require 'net/http'
require 'JSON'
url = URI({my url})

    http = Net::HTTP.new(url.host, url.port)

    request = Net::HTTP::Get.new(url)
    request["cache-control"] = 'no-cache'
    request["postman-token"] = '69430784-307c-ea1f-a488-a96cdc39e504'

    response = http.request(request)
    parsed = response.read_body

    h = JSON.parse(parsed)

    num = h["msr"].find {|h1| h1['key']=='blocker_violations'}['val']

我怀疑这个问题可能有太多关系,但是有些帮助表示赞赏!

1 个答案:

答案 0 :(得分:1)

你需要做两件事。首先,您将返回一个数组,并且您只对元素的子集感兴趣。这是一个通过过滤器解决的常见模式,或Ruby中的select。其次,您希望选择这些元素的条件还取决于另一个数组的值,您需要使用不同的技术进行过滤。你可以这样尝试:

res = [
  {
    "id": 10008,
    "name": "vpop-fms-inventory-ws-client",
    "msr": [
      {
        "key": "blocker_violations",
        "val": 123,
        "frmt_val": "0"
      }
    ]
  },
  {
    "id": 10008,
    "name": "vpop-fms-inventory-ws-client",
    "msr": [
      {
        "key": "safe",
        "val": 0,
        "frmt_val": "0"
      }
    ]
  }
]

# define a lambda function that we will use later on to filter out the blocker violations
violation = -> (h) { h[:key] == 'blocker_violations' }

# Select only those objects who contain any msr with a key of     blocker_violations
violations = res.select {|h1| h1[:msr].any? &violation }

# Which msr value should we take? Here I just take the first.
values = violations.map {|v| v[:msr].first[:val] }

此代码可能存在的问题是msr是一个数组。所以从理论上讲,你可能最终得到msr中的2个对象,一个是阻塞者违规,另一个不是。你必须决定如何处理它。在我的示例中,如果通过any?使用单个阻止程序,则将其包含在内。但是,如果所有msr个对象都是阻止程序违规,您可能只希望包含它们。您可以通过all?方法执行此操作。

您接下来面临的第二个问题是,要返回哪个值?如果msr对象中存在多个阻止程序违规,您选择哪个值?我只拿了first一个 - 但这可能不适合你。

根据您的要求,我的示例可能有用,或者您可能需要对其进行调整。

此外,如果您以前从未遇到过lambda语法,可以阅读更多相关信息here