39

从 ruby​​ 文档中,我可以看到该load方法将 proc 作为 arg 而parse没有。还有其他区别吗?比如说,当我有一个 JSON 字符串时,我应该使用哪种方法将其转换为 Ruby 对象?

load(source, proc = nil, options = {}) 从 JSON 源加载一个 ruby​​ 数据结构并返回它。源可以是类字符串对象、类 IO 对象或响应读取方法的对象。如果给出了 proc,它将以任何嵌套的 Ruby 对象作为参数以深度一阶递归方式调用。要修改默认选项,还要传入可选选项参数。此方法是 Marshal 和 YAML 的加载/转储接口实现的一部分。也别名为:restore

parse(source, opts = {}) 将 JSON 文档源解析为 Ruby 数据结构并返回。

4

5 回答 5

37

JSON#parse将 JSON 字符串解析为 Ruby 哈希。

 JSON.parse('{"name": "Some Name"}') # => {"name" => "Some Name"}

JSON#load接受字符串或 IO(文件等)并将其转换为 Ruby 哈希/数组

JSON.load File.new("names.json")     # => Reads the JSON inside the file and results in a Ruby Object.

JSON.load '{"name": "Some Name"}'    # Works just like #parse

事实上,它转换任何响应#read方法的对象。例如:

class A
  def initialize
    @a = '{"name": "Some Name"}'
  end

  def read
    @a
  end
end

JSON.load(A.new)                      # => {"name" => "Some Name"}
于 2013-06-21T03:14:38.733 回答
24

一个关键的区别是JSON.load当给定不受信任的输入时它是不安全的(同样可以用 来实现JSON.parse,但它有安全的默认值)。这是因为它提供了一种实例化“普通”Hash、String、Array、Number 类以外的类的方法:

class Foo
  def self.json_creatable?
    true
  end
  def self.json_create attributes
    puts "called with #{attributes}"
  end
end

JSON.parse('{"json_class": "Foo"}') #=> {"json_class"=>"Foo"} 

然而

JSON.load('{"json_class": "Foo"}')
called with {"json_class"=>"Foo"}
#=> nil

这旨在让您实现数据的自定义序列化 - 在解析来自广阔世界的数据时不应使用它。当然,您确实需要为此实现json_creatable?json_create方法才能真正实现任何目标,但是您对您的任何依赖项都没有这样做或method_missing以可能被滥用的方式实现有多大信心?(例如,参见Marshal.load漏洞利用。因此JSON.load&JSON.parse被显着收紧)。

JSON.parse在处理不受信任的数据或除非您需要额外的功能时,请始终使用JSON.load

于 2015-05-05T10:33:03.627 回答
20

另一个区别是JSON.load默认解析单个值(不是对象也不是数组)。

JSON.load("false")
=> false

JSON.load("123")
=> 123

JSON.parse需要quirks mode启用解析这样的值。

JSON.parse("false")
JSON::ParserError: 757: unexpected token at 'false'

JSON.parse("false", quirks_mode: true)
=> false
于 2014-10-29T10:00:54.627 回答
2

Here load the source codes click me

# File ext/json/lib/json/common.rb, line 323
def load(source, proc = nil, options = {})
  opts = load_default_options.merge options
  if source.respond_to? :to_str
    source = source.to_str
  elsif source.respond_to? :to_io
    source = source.to_io.read
  elsif source.respond_to?(:read)
    source = source.read
  end
  if opts[:allow_blank] && (source.nil? || source.empty?)
    source = 'null'
  end
  result = parse(source, opts)
  recurse_proc(result, &proc) if proc
  result
end

The first line within the method:

opts = load_default_options.merge options

We can call the JSON#load_default_options in the console:

JSON.load_default_options

=> {:max_nesting=>false, :allow_nan=>true, :quirks_mode=>true, :create_additions=>true}

We can see there're four default options, what do they mean, we can get some from here click me:

  • max_nesting: The maximum depth of nesting allowed in the parsed data structures. Disable depth checking with :max_nesting => false. It defaults to 100./
  • allow_nan: If set to true, allow NaN, Infinity and -Infinity in defiance of RFC 7159 to be parsed by the Parser. This option defaults to false.
  • symbolize_names: If set to true, returns symbols for the names (keys) in a JSON object. Otherwise, strings are returned. Strings are the default.
  • create_additions: If set to false, the Parser doesn't create additions even if a matching class and create_id was found. This option defaults to false.
  • object_class: Defaults to Hash
  • array_class: Defaults to Array

WHY

referring to JSON#parse, back to see the source codes of JSON#load, The third to last line, there is result = parse(source, opts), So load actually is a parse with four default options.

That is the reason:

JSON.load("123") #=> 123
JSON.parse("123", quirks_mode: true) #=> 123

another way, if the object to be parsed responds to to_io meaning is a File, load still makes sense. However, parse do not.

于 2019-11-06T10:34:04.153 回答
0

还有一个区别:不同的选择。
常用示例(注_keys_names):

JSON.load '{"key": "val"}', symbolize_keys: true
=> {"key" => "val"}         # parse option syntax silently ignored 

JSON.parse '{"key": "val"}', symbolize_keys: true
=> {:key => "val"}          # symbols, yay!

JSON.load '{"key": "val"}', symbolize_names: true
=> {:key => "val"}          # using the correct syntax for load
于 2017-04-23T09:40:37.120 回答