使用内置的Ruby JSON库反序列化JSON基元

为什么 Ruby的内置JSON不能反序列化简单的JSON原语,我该如何解决它?
irb(main):001:0> require 'json'
#=> true

irb(main):002:0> objects = [ {},[],42,"",true,nil ]
#=> [{},true]

irb(main):012:0> objects.each do |o|
irb(main):013:1*   json = o.to_json
irb(main):014:1>   begin
irb(main):015:2*     p JSON.parse(json)
irb(main):016:2>   rescue Exception => e
irb(main):017:2>     puts "Error parsing #{json.inspect}: #{e}"
irb(main):018:2>   end
irb(main):019:1> end
{}
[]
Error parsing "42": 706: unexpected token at '42'
Error parsing "\"\"": 706: unexpected token at '""'
Error parsing "true": 706: unexpected token at 'true'
Error parsing "null": 706: unexpected token at 'null'
#=> [{},nil]

irb(main):020:0> RUBY_DESCRIPTION
#=> "ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-darwin10.7.0]"
irb(main):022:0> JSON::VERSION
#=> "1.4.2"

解决方法

RFC 4627: The application/json Media Type for JavaScript Object Notation (JSON)有这个说:
2.  JSON Grammar

   A JSON text is a sequence of tokens.  The set of tokens includes six
   structural characters,strings,numbers,and three literal names.

   A JSON text is a serialized object or array.

      JSON-text = object / array

[...]

2.1.  Values

   A JSON value MUST be an object,array,number,or string,or one of
   the following three literal names:

      false null true

如果你在六个样本对象上调用to_json,我们得到:

>> objects = [ {},nil ]
>> objects.map { |o| puts o.to_json }
{}
[]
42
""
true
null

所以第一个和第二个是有效的JSON文本,而后四个不是有效的JSON文本,即使它们是有效的JSON值.

JSON.parse想要它所谓的JSON文档:

Parse the JSON document source into a Ruby data structure and return it.

也许JSON文档是RFC 4627称为JSON文本的库的术语.如果是这样,那么引发异常是对无效输入的合理响应.

如果你强行包装和解开所有东西:

objects.each do |o|
    json = o.to_json 
    begin
        json_text = '[' + json + ']'
        p JSON.parse(json_text)[0]
    rescue Exception => e 
        puts "Error parsing #{json.inspect}: #{e}"    
    end    
end

正如您在评论中所指出的,在调用者想要使用:symbolize_names选项的情况下,使用数组作为包装器比对象更好.像这样包装意味着你将永远为JSON.parse提供一个JSON文本,一切都应该没问题.

相关文章

以下代码导致我的问题: class Foo def initialize(n=0) @n = n end attr_accessor :n d...
这是我的spec文件,当为上下文添加测试“而不是可单独更新用户余额”时,我得到以下错误. require 's...
我有一个拦截器:DevelopmentMailInterceptor和一个启动拦截器的inititializer setup_mail.rb. 但我想将...
例如,如果我有YAML文件 en: questions: new: 'New Question' other: recent: ...
我听说在RSpec中避免它,let,let !,指定,之前和主题是最佳做法. 关于让,让!之前,如果不使用这些,我该如...
我在Rails中使用MongoDB和mongo_mapper gem,项目足够大.有什么办法可以将数据从Mongoid迁移到 Postgres...