我正在尝试解析JSON数据并创建自己的字典来显示数据的子集。问题是,我注意到我的输入数据根据扫描的内容而改变(使用nmap)。一些元素可能是数组值,而有些可能不是。这些组合看起来相当广泛。
例如,这是最简单的输入,其中只找到了IP地址:
{
'host' => {
'address' => {
'addr' => '192.168.0.1'
},
'status' => {...}
}
}
但是,可能会找到IP和MAC地址:
{
'host' => {
'address' => [{
'addrtype' => 'ipv4',
'addr' => '192.168.0.1',
},{
'addrtype' => 'mac',
'mac' => '00:AA:BB:CC:DD:EE',
},
'status' => {...}
}]
}
这只是几个例子。我见过的其他变化:
`host.class` = Array
`address.class` = Hash
`host['status'].class` = Array
etc...
当我解析输出时,我首先检查元素是否是一个数组,如果是,我以一种方式访问键/值,而如果它不是一个数组,我基本上必须复制我的代码对它进行一些调整,这似乎不是很有说服力:
hash = {}
if hosts.class == Array
hosts.each do |host|
ip = if host['address'].class == Array
host['address'][0]['addr']
else
host['address']['addr']
end
hash[ip] = {}
end
else
ip = if hosts['address'].class == Array
hosts['address'][0]['addr']
else
hosts['address']['addr']
end
hash[ip] = {}
end
puts hash
end
最后,我只是想找到一种更好/更有说服力的方法来生成如下所示的哈希,同时考虑一个元素可能/可能不是数组的可能性:
{
'192.168.0.1' => {
'mac' => '00:aa:bb:cc:dd:ee',
'vendor' => 'Apple',
'ports' => {
'80' => {
'status' => 'open',
'service' => 'httpd'
}
'443' => {
'status' => 'filtered',
'service' => 'httpd'
}
}
},
192.168.0.2 => {
...
}
}
如果有一种我尚未遇到过的红宝石方法会让它更流畅吗?
答案 0 :(得分:1)
不是真的......但是你可以把它变成一个数组,例如通过做类似的事情:
hosts = [hosts] unless hosts.is_a?(Array)
或类似...然后将其传递给您现在不重复的代码。 :)
答案 1 :(得分:0)
使用Array#wrap
代替条件,并使用Enumerable#map
代替Enumerable#each
,可以将问题中的20行代码缩减为一行:
Array.wrap(hosts).map { |host| [Array.wrap(host['address']).first['addr'], {}] }.to_h
现在真是太神奇了!