2015-09-13 15 views
6

Tôi có một phản ứng JSON mà là một mảng của Hash:Làm cách nào để chỉ định các loại dữ liệu cho phân tích cú pháp JSON?

[{"project" => {"id" => 1, "name" => "Internal"}, 
{"project" => {"id" => 2, "name" => "External"}}] 

Mã của tôi trông như thế này:

client = HTTP::Client.new(url, ssl: true) 
response = client.get("/projects", ssl: true) 
projects = JSON.parse(response.body) as Array 

này mang lại cho tôi một mảng nhưng có vẻ như tôi cần phải định kiểu các yếu tố để thực sự sử dụng chúng nếu không tôi sẽ nhận được undefined method '[]' for Nil (compile-time type is (Nil | String | Int64 | Float64 | Bool | Hash(String, JSON::Type) | Array(JSON::Type))).

Tôi đã thử as Array(Hash) nhưng điều này mang lại cho tôi can't use Hash(K, V) as generic type argument yet, use a more specific type.

Làm cách nào để chỉ định loại?

Trả lời

8

Bạn phải đúc những khi bạn truy cập vào các yếu tố:

projects = JSON.parse(json).as(Array) 
project = projects.first.as(Hash)["project"].as(Hash) 
id = project["id"].as(Int64) 

http://carc.in/#/r/f3f

Nhưng đối với dữ liệu cũng có cấu trúc như thế này bạn nên sử dụng với JSON.mapping:

class ProjectContainer 
    JSON.mapping({ 
    project: Project 
    }) 
end 

class Project 
    JSON.mapping({ 
    id: Int64, 
    name: String 
    }) 
end 

projects = Array(ProjectContainer).from_json(json) 
project = projects.first.project 
pp id = project.id 

http://carc.in/#/r/f3g

Bạn có thể xem giải thích một chút chi tiết hơn về vấn đề này tại https://github.com/manastech/crystal/issues/982#issuecomment-121156428

+1

Bạn đánh bại tôi trong 1 phút! – asterite

+0

xuất hiện cú pháp #as đã thay đổi? https://play.crystal-lang.org/#/r/1uhw hoặc bạn có thể sử dụng to_i và to_s FWIW. – rogerdpack

+0

Đúng, tôi đã cập nhật câu trả lời. –

3

Bạn tiếp tục đúc trong từng bước:

projects = JSON.parse(response.body) as Array 
projects.each do |project| 
    project = project as Hash 
    project = project["project"] as Hash 
    id = project["id"] as Int 
    name = project["name"] as String 
end 

Nhưng nếu phản ứng API của bạn có một cấu trúc nổi tiếng, tôi đề nghị bạn nên sử dụng JSON .mapping: https://crystal-lang.org/api/0.22.0/JSON.html#mapping-macro

Các vấn đề liên quan