2011-09-25 23 views
50

phép nói rằng tôi có Hash này:của Ruby JSON phân tích cú pháp thay đổi phím Hash

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

tôi có thể gọi các mảng thông tin bằng cách làm hash[:info].

Bây giờ khi tôi tắt chức năng này vào JSON (JSON.generate), và sau đó phân tích nó (JSON.parse), tôi nhận được băm này:

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

Bây giờ nếu tôi sử dụng hash[:info] nó trả nil, nhưng không nếu tôi sử dụng hash["info"].

Tại sao điều này? Và có anyway để khắc phục sự không tương thích này (ngoài việc sử dụng các phím chuỗi từ đầu)?

Trả lời

19

Tóm lại, không. Hãy suy nghĩ về nó theo cách này, lưu trữ các ký hiệu trong JSON giống như lưu trữ các chuỗi trong JSON. Vì vậy, bạn không thể phân biệt giữa hai khi nói đến phân tích cú pháp chuỗi JSON. Tất nhiên bạn có thể chuyển đổi các chuỗi ký tự trở lại thành các biểu tượng, hoặc thậm chí là xây dựng một lớp để tương tác với JSON, điều này tự động thực hiện, nhưng tôi khuyên bạn chỉ nên sử dụng các chuỗi.

Nhưng, chỉ vì lợi ích của nó, đây là câu trả lời cho câu hỏi này những lần trước nó được hỏi:

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

Hoặc có lẽ một HashWithIndifferentAccess

+0

Cảm ơn cho các liên kết, nhưng cũng giống như bạn nói, tôi sẽ chỉ cần sử dụng dây cho các phím – LanguagesNamedAfterCofee

118

Các Trình tạo JSON chuyển đổi các ký hiệu thành chuỗi vì JSON không hỗ trợ các ký hiệu. Vì các khóa JSON là tất cả các chuỗi, việc phân tích cú pháp một tài liệu JSON sẽ tạo ra một băm Ruby với các khóa chuỗi theo mặc định.

Bạn có thể yêu cầu trình phân tích cú pháp sử dụng ký hiệu thay vì chuỗi bằng cách sử dụng tùy chọn symbolize_names.

Ví dụ:

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"}] 

tham khảo: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/json/rdoc/JSON.html#method-i-parse

+0

Cảm ơn thông tin :) – LanguagesNamedAfterCofee

+0

Và Tôi nghĩ rằng đó là: symbolize_keys (http://rubydoc.info/gems/multi_json/1.3.2/MultiJson) – Boushley

+9

@Boushley: Không, nó vẫn là 'symbolize_names'. Câu trả lời của tôi tham chiếu đến công cụ JSON đi kèm với thư viện chuẩn của Ruby. Bạn đang tham chiếu đá quý của bên thứ ba. – wyattisimo

2
  1. Sử dụng ActiveSupport :: JSON.decode, nó sẽ cho phép bạn trao đổi parsers json dễ dàng hơn
  2. Sử dụng ActiveSupport :: JSON.decode (my_json, symbolize_names: true)

Điều này sẽ biểu thị đệ quy tất cả các khóa trong băm.

(được xác nhận trên ruby ​​2.0)

+0

dường như bị xóa trong đường ray 4.1? http://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#changes-in-json-handling và http://api.rubyonrails.org/classes/ActiveSupport/JSON.html nêu bật hỗ trợ tùy chọn đã xóa – nruth

4

tôi giải quyết vấn đề tương tự của tôi với cách gọi phương thức with_indifferent_access vào nó

Ở đây tôi có một chuỗi json và chúng ta có thể gán nó vào biến s

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

Vì vậy, bây giờ tôi có thể phân tích dữ liệu với lớp JSON và gán nó vào h

h = JSON.parse(s).with_indifferent_access 

Điều này sẽ tạo một hash có thể chấp nhận một chuỗi hoặc một biểu tượng như là chìa khóa

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

Đã thêm 'with_indifferent_access' vào 'Hash' thông qua một cái gì đó trong hệ sinh thái Rails? – Mark

+1

@Đảm bảo bạn là chính xác. Đây là một liên kết http://api.rubyonrails.org/v4.2.5/classes/ActiveSupport/HashWithIndifferentAccess.html –

0

Bạn không thể sử dụng tùy chọn đó như thế này

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

Trong Rails 4.1 hoặc mới hơn, ActiveSupport::JSON.decode không còn chấp nhận một tùy chọn băm cho MultiJSON. MultiJSON đã hết hạn sử dụng và đã bị xóa.

Bạn có thể sử dụng symbolize_keys để xử lý.

ActiveSupport::JSON.decode(str_json).symbolize_keys 
2

Có thể sửa đổi tất cả các phím trong một hash để chuyển đổi chúng từ một chuỗi đến một biểu tượng:

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"} 

Thật không may điều đó không làm việc cho các hash lồng vào bên trong mảng. Bạn có thể, tuy nhiên, hãy viết một chút phương pháp đệ quy có thể chuyển đổi tất cả các phím băm:

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"} 
Các vấn đề liên quan