【问题标题】:How to make Ruby JSON parser ignore json_class?如何让 Ruby JSON 解析器忽略 json_class?
【发布时间】:2014-03-12 13:14:27
【问题描述】:

我有一个序列化的 JSON 字符串(实际上是厨师角色定义),它有一个 json_class 键,使 ruby​​ JSON 解析器尝试将其强制为 Chef::Role 对象。我怎样才能让解析器忽略这个键而只是简单地反序列化成一个普通的哈希?

【问题讨论】:

    标签: ruby json chef-infra


    【解决方案1】:

    我刚刚遇到了同样的问题,并通过阅读 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 来解组转储对象。

    【讨论】:

    【解决方案2】:

    “json_class”键用于指示 json 应该被解组为什么对象。它由 JSON.dump 添加。在更新的 JSON 版本中,JSON.parse 将忽略“json_class”,取消编组为哈希。而JSON.load 将取消编组到指定的对象(在您的情况下,是 Chef::Role)。

    JSON.parse('{ "json_class": "Chef::Role" }').class => Hash
    JSON.load('{ "json_class": "Chef::Role" }').class => Chef::Role
    

    【讨论】:

    • 感谢您的更新,马特。我已经编辑了我的答案,以反映未来的路人。
    【解决方案3】:

    可以在解析之前对字符串执行gsub,然后将该特定键更改为其他键。

    展示一个前后的 JSON 样本怎么样?

    【讨论】:

      【解决方案4】:

      根据文档,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 对,那么以后仍然可能会出现问题,就像在这种情况下一样。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-10-06
        • 2018-09-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-08
        • 1970-01-01
        相关资源
        最近更新 更多