我正在将JSON结果解析为Ruby哈希。 JSON结果如下所示:
{
"records": [
{
"recordName": "7DBC4FAD-D18C-476A-89FB-14A515098F34",
"recordType": "Media",
"fields": {
"data": {
"value": {
"fileChecksum": "ABCDEFGHIJ",
"size": 9633842,
"downloadURL": "https://cvws.icloud-content.com/B/ABCDEF"
},
"type": "ASSETID"
}
},
"recordChangeTag": "ii23box2",
"created": {
"timestamp": 1449863552482,
"userRecordName": "_abcdef",
"deviceID": "12345"
},
"modified": {
"timestamp": 1449863552482,
"userRecordName": "_abcdef",
"deviceID": "12345"
}
}
]
}
我不能保证它会返回任何/所有这些值,或者每个值都是某种类型(例如数组,哈希,字符串,数字),如果我不正确地调用它,那么我得到崩溃。
现在我需要对'records'数组中的第一项使用downloadURL,或者像使用Swift库SwiftyJSON(我更熟悉)那样编写它:
json["records"][0]["fields"]["data"]["value"]["downloadURL"]
我想知道在Ruby中安全地执行此操作的最安全/最佳/标准方法是什么。也许我在想错了?
答案 0 :(得分:3)
在ruby 2.3及以上版本中,您可以使用Hash#dig
和Array#dig
json = JSON.parse(...)
json.dig('records', 0, 'fields', 'data', 'value', 'downloadURL')
如果任何中间值为零,您将获得nil。如果其中一个中间值没有dig
方法,例如,如果`json ['记录'] [0] ['字段']意外地这将引发TypeError。
答案 1 :(得分:1)
从文档(http://ruby-doc.org/stdlib-2.2.3/libdoc/json/rdoc/JSON.html):
require 'json'
my_hash = JSON.parse('{"hello": "goodbye"}')
puts my_hash["hello"] => "goodbye"
如果您担心自己可能没有某些数据。看到这个问题: Equivalent of .try() for a hash to avoid "undefined method" errors on nil?
答案 2 :(得分:1)
您可以使用递归搜索json对象中包含的每个对象
JSON模块的recurse_proc
方法。
以下是使用您提供的数据的示例。
require 'json'
json_string = '{
"records": [
{
"recordName": "7DBC4FAD-D18C-476A-89FB-14A515098F34",
"recordType": "Media",
"fields": {
"data": {
"value": {
"fileChecksum": "ABCDEFGHIJ",
"size": 9633842,
"downloadURL": "https://cvws.icloud-content.com/B/ABCDEF"
},
"type": "ASSETID"
}
},
"recordChangeTag": "ii23box2",
"created": {
"timestamp": 1449863552482,
"userRecordName": "_abcdef",
"deviceID": "12345"
},
"modified": {
"timestamp": 1449863552482,
"userRecordName": "_abcdef",
"deviceID": "12345"
}
}
]
}'
json_obj = JSON.parse(json_string)
JSON.recurse_proc(json_obj) do |obj|
if obj.is_a?(Hash) && obj['downloadURL']
puts obj['downloadURL']
end
end
我最初假设你只是想在json的某个地方找到downloadURL而不会崩溃,但根据Frederick的回答和Cary的评论,假设你只想要找到downloadURL,如果它位于完全路径,而不是它是否存在。 基于弗雷德里克的回答和Cary的评论,这里有一些其他选项可以安全地找到预期路径下的downloadURL。
path = ['records', 0, 'fields', 'data', 'value', 'downloadURL']
parsed_json_obj = JSON.parse(json_string)
node_value = path.reduce(parsed_json_obj) do |json,node|
if json.is_a?(Hash) || (json.is_a?(Array) && node.is_a?(Integer))
path = path.drop 1
json[node]
else
node unless node == path.last
end
end
puts node_value || "not_found"
path = ['records', 0, 'fields', 'data', 'value', 'downloadURL']
begin
node_value = parsed_json_obj.dig(*path)
rescue TypeError
node_value = "not_found"
end
puts node_value || "not_found"
BTW,这假设json至少是有效的,如果不是给定的,你可能也想将JSON.parse包装在begin-rescue-end块中。