【问题标题】:Ruby JSON parse changes Hash keysRuby JSON 解析更改哈希键
【发布时间】:2011-11-24 12:28:01
【问题描述】:

假设我有这个哈希:

{
  :info => [
    {
        :from => "Ryan Bates",
        :message => "sup bra",
        :time => "04:35 AM"
    }
  ]
}

我可以通过 hash[:info] 调用 info 数组。

现在当我把它转换成 JSON (JSON.generate),然后解析它 (JSON.parse),我得到了这个哈希:

{
  "info" => [
    {
        "from" => "Ryan Bates",
        "message" => "sup bra",
        "time" => "04:35 AM"
    }
  ]
}

现在,如果我使用hash[:info],它会返回nil,但如果我使用hash["info"],则不会。

这是为什么?有没有办法解决这个不兼容问题(除了从一开始就使用字符串键)?

【问题讨论】:

    标签: ruby-on-rails ruby json hash


    【解决方案1】:

    JSON 生成器将符号转换为字符串,因为 JSON 不支持符号。由于 JSON 键都是字符串,因此解析 JSON 文档会默认生成带有字符串键的 Ruby 哈希。

    您可以使用symbolize_names 选项告诉解析器使用符号而不是字符串。

    示例:

    original_hash = {:info => [{:from => "Ryan Bates", :message => "sup bra", :time => "04:35 AM"}]}
    serialized = JSON.generate(original_hash)
    new_hash = JSON.parse(serialized, {:symbolize_names => true})
    
    new_hash[:info]
     #=> [{:from=>"Ryan Bates", :message=>"sup bra", :time=>"04:35 AM"}]
    

    参考:http://www.ruby-doc.org/stdlib-1.9.3/libdoc/json/rdoc/JSON.html#method-i-parse

    【讨论】:

    • 我认为现在是 :symbolize_keys (rubydoc.info/gems/multi_json/1.3.2/MultiJson)
    • @Boushley:不,仍然是symbolize_names。我的回答引用了 Ruby 标准库附带的 JSON 引擎。您正在引用第三方 gem。
    【解决方案2】:

    简而言之,不。这样想,在 JSON 中存储符号与在 JSON 中存储字符串是一样的。因此,在解析 JSON 字符串时,您可能无法区分两者。您当然可以将字符串键转换回符号,或者实际上甚至构建一个与 JSON 交互的类,它会自动执行此操作,但我建议只使用字符串。

    但是,为了这个目的,这里是之前被问到这个问题的答案:

    what is the best way to convert a json formatted key value pair to ruby hash with symbol as key?

    ActiveSupport::JSON decode hash losing symbols

    或者也许是HashWithIndifferentAccess

    【讨论】:

    • 感谢您的链接,但就像您说的,我将使用字符串作为键
    【解决方案3】:

    我通过调用 with_indifferent_access 方法解决了我的类似问题

    这里我有一个 json 字符串,我们可以将它分配给变量 s

    s = "{\"foo\":{\"bar\":\"cool\"}}"
    

    所以现在我可以用 JSON 类解析数据并将其分配给 h

    h = JSON.parse(s).with_indifferent_access
    

    这将产生一个可以接受字符串或符号作为键的哈希

    h[:foo]["bar"]
      #=> "cool"
    

    【讨论】:

    【解决方案4】:
    1. 使用 ActiveSupport::JSON.decode,它可以让您更轻松地交换 json 解析器
    2. 使用 ActiveSupport::JSON.decode(my_json, symbolize_names: true)

    这将递归地表示散列中的所有键。

    (在 ruby​​ 2.0 上确认)

    【讨论】:

    【解决方案5】:

    可以修改散列中的所有键,将它们从字符串转换为符号:

    symbol_hash = Hash[obj.map{ |k,v| [k.to_sym, v] }]
    
    puts symbol_hash[:info]
    # => {"from"=>"Ryan Bates", "message"=>"sup bra", "time"=>"04:35 AM"}
    

    不幸的是,这不适用于嵌套在数组中的哈希。但是,您可以编写一个小递归方法来转换所有哈希键:

    def symbolize_keys(obj)
      #puts obj.class # Useful for debugging
      return obj.collect { |a| symbolize_keys(a) } if obj.is_a?(Array)
      return obj unless obj.is_a?(Hash)
      return Hash[obj.map{ |k,v| [k.to_sym, symbolize_keys(v)] }]
    end
    
    symbol_hash = symbolize_keys(hash)
    puts symbol_hash[:info]
    # => {:from=>"Ryan Bates", :message=>"sup bra", :time=>"04:35 AM"}
    

    【讨论】:

      【解决方案6】:

      你不能像这样使用那个选项

      ActiveSupport::JSON.decode(str_json, symbolize_names: true)

      在 Rails 4.1 或更高版本中,ActiveSupport::JSON.decode 不再接受 MultiJSON 的选项哈希。 MultiJSON 到了生命的尽头,并且 已被删除。

      您可以使用symbolize_keys 来处理它。 警告:它仅适用于解析为哈希的 JSON 字符串。

      ActiveSupport::JSON.decode(str_json).symbolize_keys
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-07
        • 1970-01-01
        • 1970-01-01
        • 2020-10-29
        • 2018-09-25
        • 1970-01-01
        • 2019-04-20
        • 1970-01-01
        相关资源
        最近更新 更多