我有一个序列化的JSON字符串(实际上是厨师角色定义)并且它有一个json_class键,使得ruby JSON解析器试图强制它成为Chef :: Role对象。如何让解析器忽略这个键,只是简单地反序列化为普通的Hash?
答案 0 :(得分:14)
我遇到了同样的问题,通过阅读JSON gem的源代码找到了答案 - 在尝试解析之前,只需取消设置JSON.create_id:
JSON.create_id = nil
JSON.parse('{ "json_class": "Chef::Role" }').class => Hash
编辑:请注意,由于gem的版本1.7(1.8.0是我输入此更新的最新版本),因此不再需要上述hack。 JSON#parse
现在忽略json_class
,而JSON#load
应该用于取消编组转储对象。
答案 1 :(得分:6)
“json_class”键用于指示json应该取消封送的对象。它由JSON.dump添加。在更新版本的JSON中,JSON.parse
将忽略“json_class”,解除对Hash的编组。虽然JSON.load
将对指定的对象进行解组(在您的情况下,为Chef :: Role)。
JSON.parse('{ "json_class": "Chef::Role" }').class => Hash
JSON.load('{ "json_class": "Chef::Role" }').class => Chef::Role
答案 2 :(得分:0)
您可以在解析之前对字符串执行gsub
,并将该特定键更改为其他内容。
如何在前后显示JSON样本?
答案 3 :(得分:0)
根据文档,Mark Reed的解决方案当然应该有效。但是当我在Vagrantfile中尝试这个时:
JSON.create_id = nil
vagrant_json = JSON.parse(Pathname(__FILE__).dirname.join('nodes', "#{node_name}.json").read)
config.vm.provision :chef_solo do |chef|
chef.cookbooks_path = ["cookbooks", "site-cookbooks"]
chef.roles_path = "roles"
chef.data_bags_path = "data_bags"
chef.node_name = node_name
chef.run_list = vagrant_json.delete('run_list')
chef.json = vagrant_json
end
vagrant_json.class是一个Hash,但只要node.json文件包含“json_class”:“Chef :: Node”条目,它仍会在内部保留json_class值。然后当使用散列在最后一行中设置chef.json值时,它再次使用json类进行解释(奇怪的是,结果是一个空的运行列表。)
这是有效的。同样的想法,但一点点技巧:
vagrant_json = JSON.parse(Pathname(__FILE__).dirname.join('nodes', "#{node_name}.json").read)
vagrant_json['json_class'] = nil # <== This worked
config.vm.provision :chef_solo do |chef|
chef.cookbooks_path = ["cookbooks", "site-cookbooks"]
chef.roles_path = "roles"
chef.data_bags_path = "data_bags"
chef.node_name = node_name
chef.run_list = vagrant_json.delete('run_list')
chef.json = vagrant_json
end
此代码用于设置来自Chef节点文件的json属性和运行列表,包含或不包含“json_class”:“Chef :: Node”条目。
总之,前面的答案在从JSON.parse获取哈希方面似乎完全正确,但是如果你不从该哈希中删除json_class对,那么以后仍然会有麻烦,就像在这种情况下一样。