如何在Sinatra上解析Ruby中更复杂的JSON对象

时间:2013-08-03 14:36:12

标签: ruby json sinatra

我是一个Java人,是Ruby的新手。我一直在玩它只是为了看它能做什么,而我遇到了一个我无法解决的问题。

我决定再次尝试Sinatra,看看它能做些什么,并决定使用ESPN API,看看我是否可以通过API拉动团队的场地。

我能够拨打电话并获取数据,但我在解析它时遇到了问题:

{"sports"=>[{"name"=>"baseball", "id"=>1, "uid"=>"s:1", "leagues"=>[{"name"=>"Major League Baseball", "abbreviation"=>"mlb", "id"=>10, "uid"=>"s:1~l:10", "groupId"=>9, "shortName"=>"MLB", "teams"=>[{"id"=>17, "uid"=>"s:1~l:10~t:17", "location"=>"Cincinnati", "name"=>"Reds", "abbreviation"=>"CIN", "color"=>"D60042", "venues"=>[{"id"=>83, "name"=>"Great American Ball Park", "city"=>"Cincinnati", "state"=>"Ohio", "country"=>"", "capacity"=>0}], "links"=>{"api"=>{"teams"=>{"href"=>"http://api.espn.com/v1/sports/baseball/mlb/teams/17"}, "news"=>{"href"=>"http://api.espn.com/v1/sports/baseball/mlb/teams/17/news"}, "notes"=>{"href"=>"http://api.espn.com/v1/sports/baseball/mlb/teams/17/news/notes"}}, "web"=>{"teams"=>{"href"=>"http://espn.go.com/mlb/team/_/name/cin/cincinnati-reds?ex_cid=espnapi_public"}}, "mobile"=>{"teams"=>{"href"=>"http://m.espn.go.com/mlb/clubhouse?teamId=17&ex_cid=espnapi_public"}}}}]}]}], "resultsOffset"=>0, "resultsLimit"=>50, "resultsCount"=>1, "timestamp"=>"2013-08-04T14:47:13Z", "status"=>"success"}

我想拉出对象的场地部分,特别是名称值。每次我尝试解析它时,我最终得到的错误是“无法从nil更改为string”,然后我还得到一个整数到字符串错误。

这是我到目前为止所拥有的:

get '/venue/:team' do

    id = ids[params[:team]]
    url = 'http://api.espn.com/v1/sports/baseball/mlb/teams/' + id + '?enable=venues&apikey=' + $key
    resp = Net::HTTP.get_response(URI.parse(url))
    data = resp.body
    parsed = JSON.parse(resp.body)
    #venueData = parsed["sports"]

    "Looking for the venue of the #{params[:team]}, which has id " + id + ", and here's the data returned: " + venueData.to_s

end

当我解析[“sports”}时,我得到:

 [{"name"=>"baseball", "id"=>1, "uid"=>"s:1", "leagues"=>[{"name"=>"Major League Baseball", "abbreviation"=>"mlb", "id"=>10, "uid"=>"s:1~l:10", "groupId"=>9, "shortName"=>"MLB", "teams"=>[{"id"=>17, "uid"=>"s:1~l:10~t:17", "location"=>"Cincinnati", "name"=>"Reds", "abbreviation"=>"CIN", "color"=>"D60042", "venues"=>[{"id"=>83, "name"=>"Great American Ball Park", "city"=>"Cincinnati", "state"=>"Ohio", "country"=>"", "capacity"=>0}], "links"=>{"api"=>{"teams"=>{"href"=>"http://api.espn.com/v1/sports/baseball/mlb/teams/17"}, "news"=>{"href"=>"http://api.espn.com/v1/sports/baseball/mlb/teams/17/news"}, "notes"=>{"href"=>"http://api.espn.com/v1/sports/baseball/mlb/teams/17/news/notes"}}, "web"=>{"teams"=>{"href"=>"http://espn.go.com/mlb/team/_/name/cin/cincinnati-reds?ex_cid=espnapi_public"}}, "mobile"=>{"teams"=>{"href"=>"http://m.espn.go.com/mlb/clubhouse?teamId=17&ex_cid=espnapi_public"}}}}]}]}]

但没有别的东西可以解析。请帮忙!

就像我说的那样,我不是想做任何花哨的事情,只是想知道Ruby有点乐趣,但我已经坚持这个问题好几天了。任何帮助,将不胜感激!

编辑:

直接来自API的JSON:

{"sports" :[{"name" :"baseball","id" :1,"uid" :"s:1","leagues" :[{"name" :"Major League Baseball","abbreviation" :"mlb","id" :10,"uid" :"s:1~l:10","groupId" :9,"shortName" :"MLB","teams" :[{"id" :17,"uid" :"s:1~l:10~t:17","location" :"Cincinnati","name" :"Reds","abbreviation" :"CIN","color" :"D60042","venues" :[{"id" :83,"name" :"Great American Ball Park","city" :"Cincinnati","state" :"Ohio","country" :"","capacity" :0}],"links" :{"api" :{"teams" :{"href" :"http://api.espn.com/v1/sports/baseball/mlb/teams/17"},"news" :{"href" :"http://api.espn.com/v1/sports/baseball/mlb/teams/17/news"},"notes" :{"href" :"http://api.espn.com/v1/sports/baseball/mlb/teams/17/news/notes"}},"web" :{"teams" :{"href" :"http://espn.go.com/mlb/team/_/name/cin/cincinnati-reds?ex_cid=espnapi_public"}},"mobile" :{"teams" :{"href" :"http://m.espn.go.com/mlb/clubhouse?teamId=17&ex_cid=espnapi_public"}}}}]}]}],"resultsOffset" :0,"resultsLimit" :50,"resultsCount" :1,"timestamp" :"2013-08-05T19:44:32Z","status" :"success"}

data.inspect的结果:

"{\"sports\" :[{\"name\" :\"baseball\",\"id\" :1,\"uid\" :\"s:1\",\"leagues\" :[{\"name\" :\"Major League Baseball\",\"abbreviation\" :\"mlb\",\"id\" :10,\"uid\" :\"s:1~l:10\",\"groupId\" :9,\"shortName\" :\"MLB\",\"teams\" :[{\"id\" :17,\"uid\" :\"s:1~l:10~t:17\",\"location\" :\"Cincinnati\",\"name\" :\"Reds\",\"abbreviation\" :\"CIN\",\"color\" :\"D60042\",\"venues\" :[{\"id\" :83,\"name\" :\"Great American Ball Park\",\"city\" :\"Cincinnati\",\"state\" :\"Ohio\",\"country\" :\"\",\"capacity\" :0}],\"links\" :{\"api\" :{\"teams\" :{\"href\" :\"http://api.espn.com/v1/sports/baseball/mlb/teams/17\"},\"news\" :{\"href\" :\"http://api.espn.com/v1/sports/baseball/mlb/teams/17/news\"},\"notes\" :{\"href\" :\"http://api.espn.com/v1/sports/baseball/mlb/teams/17/news/notes\"}},\"web\" :{\"teams\" :{\"href\" :\"http://espn.go.com/mlb/team/_/name/cin/cincinnati-reds?ex_cid=espnapi_public\"}},\"mobile\" :{\"teams\" :{\"href\" :\"http://m.espn.go.com/mlb/clubhouse?teamId=17&ex_cid=espnapi_public\"}}}}]}]}],\"resultsOffset\" :0,\"resultsLimit\" :50,\"resultsCount\" :1,\"timestamp\" :\"2013-08-05T19:44:24Z\",\"status\" :\"success\"}"

2 个答案:

答案 0 :(得分:1)

parsed["sports"]不存在,解析您的输入并检查/转储它

答案 1 :(得分:0)

使用您在问题中提供的data,您可以获得venues这样的信息:

require 'json'

json = JSON.parse data

json["sports"].first["leagues"].first["teams"].first["venues"]
# => [{"id"=>83, "name"=>"Great American Ball Park", "city"=>"Cincinnati", "state"=>"Ohio", "country"=>"", "capacity"=>0}]

通过使用迭代器替换每个first调用,您可以在不知道数据位置的情况下进行搜索:

json["sports"].each{|h|
  h["leagues"].each{|h|
    h["teams"].each{|h|
      venues = h["venues"].map{|h| h["name"]}.join(", ")
      puts %Q!name: #{h["location"]} #{h["name"]} venues: #{venues}!
    }
  }
}

输出:

  

名称:辛辛那提红人队场地:伟大的美国棒球场

根据响应数据的稳定性,您可以删除几个迭代器:

json["sports"].first["leagues"]
              .first["teams"]
              .each{|h|
                venues = h["venues"].map{|h| h["name"] }.join(", ")
                puts %Q!name: #{h["location"]} #{h["name"]} venues: #{venues}!
              }

并且您很可能希望保存数据,因此each_with_object之类的内容非常有用:

team_and_venues = json["sports"].first["leagues"]
              .first["teams"]
              .each_with_object([]){|h,xs|
                venues = h["venues"].map{|h| h["name"]}.join(", ")
                xs << %Q!name: #{h["location"]} #{h["name"]} venues: #{venues}!
              }
# => ["name: Cincinnati Reds venues: Great American Ball Park"]

team_and_venues
# => ["name: Cincinnati Reds venues: Great American Ball Park"]

请注意,当迭代器声明变量时,即使块外有一个同名的变量,也会遵循块的范围,并且块的变量保持在本地。

如果你问我,这是一些非常难看的代码,但这是一个开始的地方。