模組 JSON

JavaScript 物件表示法 (JSON)

JSON 是一種輕量級資料交換格式。

JSON 值為下列其中之一

JSON 陣列或物件可以包含任何深度層次的巢狀陣列、物件和純量

{"foo": {"bar": 1, "baz": 2}, "bat": [0, 1, 2]}
[{"foo": 0, "bar": 1}, ["baz", 2]]

使用模組 JSON

若要在程式碼中使用模組 JSON,請從以下開始

require 'json'

這裡的所有範例都假設已執行此動作。

剖析 JSON

您可以使用下列兩種方法之一剖析包含 JSON 資料的字串

其中

這兩種方法的差別在於 JSON.parse! 會省略一些檢查,可能不適用於某些 source 資料;僅對來自受信任來源的資料使用它。對較不值得信任的來源,請使用較安全的 JSON.parse 方法。

剖析 JSON 陣列

source 是 JSON 陣列時,JSON.parse 預設會傳回 Ruby 陣列

json = '["foo", 1, 1.0, 2.0e2, true, false, null]'
ruby = JSON.parse(json)
ruby # => ["foo", 1, 1.0, 200.0, true, false, nil]
ruby.class # => Array

JSON 陣列可以包含任何深度層次的巢狀陣列、物件和純量

json = '[{"foo": 0, "bar": 1}, ["baz", 2]]'
JSON.parse(json) # => [{"foo"=>0, "bar"=>1}, ["baz", 2]]

剖析 JSON 物件

當來源為 JSON 物件時,JSON.parse 預設會傳回 Ruby Hash

json = '{"a": "foo", "b": 1, "c": 1.0, "d": 2.0e2, "e": true, "f": false, "g": null}'
ruby = JSON.parse(json)
ruby # => {"a"=>"foo", "b"=>1, "c"=>1.0, "d"=>200.0, "e"=>true, "f"=>false, "g"=>nil}
ruby.class # => Hash

JSON 物件可能包含任何深度的巢狀陣列、物件和純量

json = '{"foo": {"bar": 1, "baz": 2}, "bat": [0, 1, 2]}'
JSON.parse(json) # => {"foo"=>{"bar"=>1, "baz"=>2}, "bat"=>[0, 1, 2]}

剖析 JSON 純量

當來源為 JSON 純量(不是陣列或物件)時,JSON.parse 會傳回 Ruby 純量。

字串

ruby = JSON.parse('"foo"')
ruby # => 'foo'
ruby.class # => String

整數

ruby = JSON.parse('1')
ruby # => 1
ruby.class # => Integer

浮點數

ruby = JSON.parse('1.0')
ruby # => 1.0
ruby.class # => Float
ruby = JSON.parse('2.0e2')
ruby # => 200
ruby.class # => Float

布林值

ruby = JSON.parse('true')
ruby # => true
ruby.class # => TrueClass
ruby = JSON.parse('false')
ruby # => false
ruby.class # => FalseClass

Null

ruby = JSON.parse('null')
ruby # => nil
ruby.class # => NilClass

剖析選項

輸入選項

選項 max_nesting(整數)指定允許的最大巢狀深度;預設為 100;指定 false 以停用深度檢查。

使用預設值 false

source = '[0, [1, [2, [3]]]]'
ruby = JSON.parse(source)
ruby # => [0, [1, [2, [3]]]]

太深

# Raises JSON::NestingError (nesting of 2 is too deep):
JSON.parse(source, {max_nesting: 1})

錯誤值

# Raises TypeError (wrong argument type Symbol (expected Fixnum)):
JSON.parse(source, {max_nesting: :foo})

選項 allow_nan(布林值)指定是否允許在 來源 中使用 NaNInfinityMinusInfinity;預設為 false

使用預設值 false

# Raises JSON::ParserError (225: unexpected token at '[NaN]'):
JSON.parse('[NaN]')
# Raises JSON::ParserError (232: unexpected token at '[Infinity]'):
JSON.parse('[Infinity]')
# Raises JSON::ParserError (248: unexpected token at '[-Infinity]'):
JSON.parse('[-Infinity]')

允許

source = '[NaN, Infinity, -Infinity]'
ruby = JSON.parse(source, {allow_nan: true})
ruby # => [NaN, Infinity, -Infinity]
輸出選項

選項 symbolize_names(布林值)指定傳回的 Hash 金鑰是否應為符號;預設為 false(使用字串)。

使用預設值 false

source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
ruby = JSON.parse(source)
ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}

使用符號

ruby = JSON.parse(source, {symbolize_names: true})
ruby # => {:a=>"foo", :b=>1.0, :c=>true, :d=>false, :e=>nil}

選項 object_class(類別)指定要對每個 JSON 物件使用的 Ruby 類別;預設為 Hash。

使用預設值 Hash

source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
ruby = JSON.parse(source)
ruby.class # => Hash

使用類別 OpenStruct

ruby = JSON.parse(source, {object_class: OpenStruct})
ruby # => #<OpenStruct a="foo", b=1.0, c=true, d=false, e=nil>

選項 array_class(類別)指定要對每個 JSON 陣列使用的 Ruby 類別;預設為 Array。

使用預設值 Array

source = '["foo", 1.0, true, false, null]'
ruby = JSON.parse(source)
ruby.class # => Array

使用類別 Set

ruby = JSON.parse(source, {array_class: Set})
ruby # => #<Set: {"foo", 1.0, true, false, nil}>

選項 create_additions(布林值)指定是否在剖析時使用 JSON 新增功能。請參閱 JSON 新增功能

產生 JSON

若要產生包含 JSON 資料的 Ruby 字串,請使用函式 JSON.generate(source, opts),其中

從陣列產生 JSON

當來源為 Ruby 陣列時,JSON.generate 會傳回包含 JSON 陣列的字串

ruby = [0, 's', :foo]
json = JSON.generate(ruby)
json # => '[0,"s","foo"]'

Ruby 陣列 array 可能包含任何深度的巢狀陣列、雜湊和純量

ruby = [0, [1, 2], {foo: 3, bar: 4}]
json = JSON.generate(ruby)
json # => '[0,[1,2],{"foo":3,"bar":4}]'

從雜湊產生 JSON

當來源為 Ruby 雜湊時,JSON.generate 會傳回包含 JSON 物件的字串

ruby = {foo: 0, bar: 's', baz: :bat}
json = JSON.generate(ruby)
json # => '{"foo":0,"bar":"s","baz":"bat"}'

Ruby 雜湊陣列可能包含任何深度的巢狀陣列、雜湊和純量

ruby = {foo: [0, 1], bar: {baz: 2, bat: 3}, bam: :bad}
json = JSON.generate(ruby)
json # => '{"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}'

從其他物件產生 JSON

當來源既不是陣列也不是雜湊時,產生的 JSON 資料會根據來源的類別而定。

當來源是 Ruby 整數或浮點數時,JSON.generate 會傳回包含 JSON 數字的字串

JSON.generate(42) # => '42'
JSON.generate(0.42) # => '0.42'

當來源是 Ruby 字串時,JSON.generate 會傳回包含 JSON 字串(帶雙引號)的字串

JSON.generate('A string') # => '"A string"'

當來源是 truefalsenil 時,JSON.generate 會傳回包含對應 JSON 權杖的字串

JSON.generate(true) # => 'true'
JSON.generate(false) # => 'false'
JSON.generate(nil) # => 'null'

當來源不是以上任何一種時,JSON.generate 會傳回包含來源的 JSON 字串表示的字串

JSON.generate(:foo) # => '"foo"'
JSON.generate(Complex(0, 0)) # => '"0+0i"'
JSON.generate(Dir.new('.')) # => '"#<Dir>"'

產生選項

輸入選項

選項 allow_nan (布林值) 指定是否可以產生 NaNInfinity-Infinity;預設為 false

使用預設值 false

# Raises JSON::GeneratorError (920: NaN not allowed in JSON):
JSON.generate(JSON::NaN)
# Raises JSON::GeneratorError (917: Infinity not allowed in JSON):
JSON.generate(JSON::Infinity)
# Raises JSON::GeneratorError (917: -Infinity not allowed in JSON):
JSON.generate(JSON::MinusInfinity)

允許

ruby = [Float::NaN, Float::Infinity, Float::MinusInfinity]
JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,-Infinity]'

選項 max_nesting (整數) 指定 obj 中的最大巢狀深度;預設為 100

使用預設值 100

obj = [[[[[[0]]]]]]
JSON.generate(obj) # => '[[[[[[0]]]]]]'

太深

# Raises JSON::NestingError (nesting of 2 is too deep):
JSON.generate(obj, max_nesting: 2)
跳脫選項

選項 script_safe (布林值) 指定是否要跳脫 '\u2028''\u2029''/',以使 JSON 物件可以安全地內插到腳本標籤中。

選項 ascii_only (布林值) 指定是否要跳脫 ASCII 範圍之外的所有字元。

輸出選項

預設格式化選項會產生最精簡的 JSON 資料,全部都在一行上,沒有空白。

您可以使用這些格式化選項以更開放的格式產生 JSON 資料,使用空白。另請參閱 JSON.pretty_generate

在此範例中,obj 先用於產生最短的 JSON 資料 (沒有空白),然後再使用所有指定的格式選項

obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}}
json = JSON.generate(obj)
puts 'Compact:', json
opts = {
  array_nl: "\n",
  object_nl: "\n",
  indent: '  ',
  space_before: ' ',
  space: ' '
}
puts 'Open:', JSON.generate(obj, opts)

輸出

Compact:
{"foo":["bar","baz"],"bat":{"bam":0,"bad":1}}
Open:
{
  "foo" : [
    "bar",
    "baz"
],
  "bat" : {
    "bam" : 0,
    "bad" : 1
  }
}

JSON 新增

當您將非字串物件從 Ruby 轉換為 JSON 再轉換回來時,您會得到一個新的字串,而不是您一開始的物件

ruby0 = Range.new(0, 2)
json = JSON.generate(ruby0)
json # => '0..2"'
ruby1 = JSON.parse(json)
ruby1 # => '0..2'
ruby1.class # => String

您可以使用 JSON 新增來保留原始物件。新增是 Ruby 類別的延伸,因此

此範例顯示將 Range 產生為 JSON 並解析回 Ruby,有和沒有 Range 新增

ruby = Range.new(0, 2)
# This passage does not use the addition for Range.
json0 = JSON.generate(ruby)
ruby0 = JSON.parse(json0)
# This passage uses the addition for Range.
require 'json/add/range'
json1 = JSON.generate(ruby)
ruby1 = JSON.parse(json1, create_additions: true)
# Make a nice display.
display = <<EOT
Generated JSON:
  Without addition:  #{json0} (#{json0.class})
  With addition:     #{json1} (#{json1.class})
Parsed JSON:
  Without addition:  #{ruby0.inspect} (#{ruby0.class})
  With addition:     #{ruby1.inspect} (#{ruby1.class})
EOT
puts display

此輸出顯示不同的結果

Generated JSON:
  Without addition:  "0..2" (String)
  With addition:     {"json_class":"Range","a":[0,2,false]} (String)
Parsed JSON:
  Without addition:  "0..2" (String)
  With addition:     0..2 (Range)

JSON 模組包含特定類別的新增。您也可以製作自訂新增。請參閱 自訂 JSON 新增

內建新增

JSON 模組包含特定類別的新增。若要使用新增,請 require 其來源

為了減少標點符號的混亂,以下範例會透過 puts 顯示產生的 JSON,而不是平常的 inspect

BigDecimal

require 'json/add/bigdecimal'
ruby0 = BigDecimal(0) # 0.0
json = JSON.generate(ruby0) # {"json_class":"BigDecimal","b":"27:0.0"}
ruby1 = JSON.parse(json, create_additions: true) # 0.0
ruby1.class # => BigDecimal

複數

require 'json/add/complex'
ruby0 = Complex(1+0i) # 1+0i
json = JSON.generate(ruby0) # {"json_class":"Complex","r":1,"i":0}
ruby1 = JSON.parse(json, create_additions: true) # 1+0i
ruby1.class # Complex

日期

require 'json/add/date'
ruby0 = Date.today # 2020-05-02
json = JSON.generate(ruby0) # {"json_class":"Date","y":2020,"m":5,"d":2,"sg":2299161.0}
ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02
ruby1.class # Date

日期時間

require 'json/add/date_time'
ruby0 = DateTime.now # 2020-05-02T10:38:13-05:00
json = JSON.generate(ruby0) # {"json_class":"DateTime","y":2020,"m":5,"d":2,"H":10,"M":38,"S":13,"of":"-5/24","sg":2299161.0}
ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02T10:38:13-05:00
ruby1.class # DateTime

例外(及其子類別,包括 RuntimeError)

require 'json/add/exception'
ruby0 = Exception.new('A message') # A message
json = JSON.generate(ruby0) # {"json_class":"Exception","m":"A message","b":null}
ruby1 = JSON.parse(json, create_additions: true) # A message
ruby1.class # Exception
ruby0 = RuntimeError.new('Another message') # Another message
json = JSON.generate(ruby0) # {"json_class":"RuntimeError","m":"Another message","b":null}
ruby1 = JSON.parse(json, create_additions: true) # Another message
ruby1.class # RuntimeError

OpenStruct

require 'json/add/ostruct'
ruby0 = OpenStruct.new(name: 'Matz', language: 'Ruby') # #<OpenStruct name="Matz", language="Ruby">
json = JSON.generate(ruby0) # {"json_class":"OpenStruct","t":{"name":"Matz","language":"Ruby"}}
ruby1 = JSON.parse(json, create_additions: true) # #<OpenStruct name="Matz", language="Ruby">
ruby1.class # OpenStruct

範圍

require 'json/add/range'
ruby0 = Range.new(0, 2) # 0..2
json = JSON.generate(ruby0) # {"json_class":"Range","a":[0,2,false]}
ruby1 = JSON.parse(json, create_additions: true) # 0..2
ruby1.class # Range

有理數

require 'json/add/rational'
ruby0 = Rational(1, 3) # 1/3
json = JSON.generate(ruby0) # {"json_class":"Rational","n":1,"d":3}
ruby1 = JSON.parse(json, create_additions: true) # 1/3
ruby1.class # Rational

正規表示法

require 'json/add/regexp'
ruby0 = Regexp.new('foo') # (?-mix:foo)
json = JSON.generate(ruby0) # {"json_class":"Regexp","o":0,"s":"foo"}
ruby1 = JSON.parse(json, create_additions: true) # (?-mix:foo)
ruby1.class # Regexp

集合

require 'json/add/set'
ruby0 = Set.new([0, 1, 2]) # #<Set: {0, 1, 2}>
json = JSON.generate(ruby0) # {"json_class":"Set","a":[0,1,2]}
ruby1 = JSON.parse(json, create_additions: true) # #<Set: {0, 1, 2}>
ruby1.class # Set

結構

require 'json/add/struct'
Customer = Struct.new(:name, :address) # Customer
ruby0 = Customer.new("Dave", "123 Main") # #<struct Customer name="Dave", address="123 Main">
json = JSON.generate(ruby0) # {"json_class":"Customer","v":["Dave","123 Main"]}
ruby1 = JSON.parse(json, create_additions: true) # #<struct Customer name="Dave", address="123 Main">
ruby1.class # Customer

符號

require 'json/add/symbol'
ruby0 = :foo # foo
json = JSON.generate(ruby0) # {"json_class":"Symbol","s":"foo"}
ruby1 = JSON.parse(json, create_additions: true) # foo
ruby1.class # Symbol

時間

require 'json/add/time'
ruby0 = Time.now # 2020-05-02 11:28:26 -0500
json = JSON.generate(ruby0) # {"json_class":"Time","s":1588436906,"n":840560000}
ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02 11:28:26 -0500
ruby1.class # Time

自訂 JSON 新增

除了提供的 JSON 新增之外,您也可以為 Ruby 內建類別或使用者定義類別建立自訂 JSON 新增。

以下是使用者定義的類別 Foo

class Foo
  attr_accessor :bar, :baz
  def initialize(bar, baz)
    self.bar = bar
    self.baz = baz
  end
end

以下是它的 JSON 新增

# Extend class Foo with JSON addition.
class Foo
  # Serialize Foo object with its class name and arguments
  def to_json(*args)
    {
      JSON.create_id  => self.class.name,
      'a'             => [ bar, baz ]
    }.to_json(*args)
  end
  # Deserialize JSON string by constructing new Foo object with arguments.
  def self.json_create(object)
    new(*object['a'])
  end
end

示範

require 'json'
# This Foo object has no custom addition.
foo0 = Foo.new(0, 1)
json0 = JSON.generate(foo0)
obj0 = JSON.parse(json0)
# Lood the custom addition.
require_relative 'foo_addition'
# This foo has the custom addition.
foo1 = Foo.new(0, 1)
json1 = JSON.generate(foo1)
obj1 = JSON.parse(json1, create_additions: true)
#   Make a nice display.
display = <<EOT
Generated JSON:
  Without custom addition:  #{json0} (#{json0.class})
  With custom addition:     #{json1} (#{json1.class})
Parsed JSON:
  Without custom addition:  #{obj0.inspect} (#{obj0.class})
  With custom addition:     #{obj1.inspect} (#{obj1.class})
EOT
puts display

輸出

Generated JSON:
  Without custom addition:  "#<Foo:0x0000000006534e80>" (String)
  With custom addition:     {"json_class":"Foo","a":[0,1]} (String)
Parsed JSON:
  Without custom addition:  "#<Foo:0x0000000006534e80>" (String)
  With custom addition:     #<Foo:0x0000000006473bb8 @bar=0, @baz=1> (Foo)

常數

CREATE_ID_TLS_KEY
DEFAULT_CREATE_ID
Infinity
JSON_LOADED
MinusInfinity
NOT_SET
NaN
VERSION

JSON 版本

屬性

dump_default_options[RW]

設定或傳回 JSON.dump 方法的預設選項。最初

opts = JSON.dump_default_options
opts # => {:max_nesting=>false, :allow_nan=>true, :script_safe=>false}
generator[R]

傳回 JSON 使用的 JSON 產生器模組。可能是 JSON::Ext::Generator 或 JSON::Pure::Generator

JSON.generator # => JSON::Ext::Generator
load_default_options[RW]

設定或傳回 JSON.load 方法的預設選項。最初

opts = JSON.load_default_options
opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
parser[R]

傳回 JSON 使用的 JSON 解析器類別。可能是 JSON::Ext::Parser 或 JSON::Pure::Parser

JSON.parser # => JSON::Ext::Parser
state[RW]

設定或傳回 JSON 使用的 JSON 產生器狀態類別。可能是 JSON::Ext::Generator::State 或 JSON::Pure::Generator::State

JSON.state # => JSON::Ext::Generator::State

公開類別方法

JSON[object] → new_array or new_string 按一下切換來源

如果 object 是字串,則呼叫 JSON.parse,並使用 objectopts(請參閱方法 parse

json = '[0, 1, null]'
JSON[json]# => [0, 1, nil]

否則,呼叫 JSON.generate,並帶有 objectopts(請參閱方法 generate

ruby = [0, 1, nil]
JSON[ruby] # => '[0,1,null]'
# File ext/json/lib/json/common.rb, line 21
def [](object, opts = {})
  if object.respond_to? :to_str
    JSON.parse(object.to_str, opts)
  else
    JSON.generate(object, opts)
  end
end
create_fast_state() 按一下以切換來源
# File ext/json/lib/json/common.rb, line 84
def create_fast_state
  State.new(
    :indent         => '',
    :space          => '',
    :object_nl      => "",
    :array_nl       => "",
    :max_nesting    => false
  )
end
create_id() 按一下以切換來源

傳回目前的建立識別碼。另請參閱 JSON.create_id=

# File ext/json/lib/json/common.rb, line 129
def self.create_id
  Thread.current[CREATE_ID_TLS_KEY] || DEFAULT_CREATE_ID
end
create_id=(new_value) 按一下以切換來源

設定建立識別碼,用於決定是否應呼叫類別的 json_create 掛鉤;初始值為 json_class

JSON.create_id # => 'json_class'
# File ext/json/lib/json/common.rb, line 123
def self.create_id=(new_value)
  Thread.current[CREATE_ID_TLS_KEY] = new_value.dup.freeze
end
create_pretty_state() 按一下以切換來源
# File ext/json/lib/json/common.rb, line 94
def create_pretty_state
  State.new(
    :indent         => '  ',
    :space          => ' ',
    :object_nl      => "\n",
    :array_nl       => "\n"
  )
end
iconv(to, from, string) 按一下以切換來源

使用 String.encode 對字串進行編碼。

# File ext/json/lib/json/common.rb, line 638
def self.iconv(to, from, string)
  string.encode(to, from)
end
restore
別名:load

公開實例方法

dump(obj, io = nil, limit = nil) 按一下以切換來源

obj 轉儲為 JSON 字串,即在物件上呼叫 generate 並傳回結果。

預設選項可透過方法 JSON.dump_default_options 進行變更。

  • 如果提供引數 io,則它應回應方法 write;JSON 字串會寫入 io,並傳回 io。如果未提供 io,則會傳回 JSON 字串。

  • 如果提供引數 limit,則會將其傳遞給 JSON.generate 作為選項 max_nesting


當未提供引數 io 時,傳回從 obj 產生的 JSON 字串

obj = {foo: [0, 1], bar: {baz: 2, bat: 3}, bam: :bad}
json = JSON.dump(obj)
json # => "{\"foo\":[0,1],\"bar\":{\"baz\":2,\"bat\":3},\"bam\":\"bad\"}"

當提供引數 io 時,將 JSON 字串寫入 io 並傳回 io

path = 't.json'
File.open(path, 'w') do |file|
  JSON.dump(obj, file)
end # => #<File:t.json (closed)>
puts File.read(path)

輸出

{"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
# File ext/json/lib/json/common.rb, line 614
def dump(obj, anIO = nil, limit = nil, kwargs = nil)
  io_limit_opt = [anIO, limit, kwargs].compact
  kwargs = io_limit_opt.pop if io_limit_opt.last.is_a?(Hash)
  anIO, limit = io_limit_opt
  if anIO.respond_to?(:to_io)
    anIO = anIO.to_io
  elsif limit.nil? && !anIO.respond_to?(:write)
    anIO, limit = nil, anIO
  end
  opts = JSON.dump_default_options
  opts = opts.merge(:max_nesting => limit) if limit
  opts = merge_dump_options(opts, **kwargs) if kwargs
  result = generate(obj, opts)
  if anIO
    anIO.write result
    anIO
  else
    result
  end
rescue JSON::NestingError
  raise ArgumentError, "exceed depth limit"
end
fast_generate(obj, opts) → new_string 按一下以切換來源

此處的引數 objoptsJSON.generate 中的引數 objopts 相同。

預設情況下,會產生 JSON 資料,而不會檢查 obj 中是否有循環參照(選項 max_nesting 設定為 false,已停用)。

如果 obj 包含循環參照,則會引發例外狀況

a = []; b = []; a.push(b); b.push(a)
# Raises SystemStackError (stack level too deep):
JSON.fast_generate(a)
# File ext/json/lib/json/common.rb, line 328
def fast_generate(obj, opts = nil)
  if State === opts
    state = opts
  else
    state = JSON.create_fast_state.configure(opts)
  end
  state.generate(obj)
end
generate(obj, opts = nil) → new_string 按一下以切換來源

傳回包含已產生 JSON 資料的字串。

另請參閱 JSON.fast_generateJSON.pretty_generate

引數 obj 是要轉換為 JSON 的 Ruby 物件。

如果提供引數 opts,則它會包含一個選項雜湊,供產生使用。請參閱 產生選項


obj 是陣列時,傳回包含 JSON 陣列的字串

obj = ["foo", 1.0, true, false, nil]
json = JSON.generate(obj)
json # => '["foo",1.0,true,false,null]'

obj 是雜湊時,傳回包含 JSON 物件的字串

obj = {foo: 0, bar: 's', baz: :bat}
json = JSON.generate(obj)
json # => '{"foo":0,"bar":"s","baz":"bat"}'

如需從其他 Ruby 物件產生範例,請參閱 從其他物件產生 JSON


如果任何格式化選項不是字串,會擲回例外。

如果 obj 包含循環參照,則會引發例外狀況

a = []; b = []; a.push(b); b.push(a)
# Raises JSON::NestingError (nesting of 100 is too deep):
JSON.generate(a)
# File ext/json/lib/json/common.rb, line 299
def generate(obj, opts = nil)
  if State === opts
    state = opts
  else
    state = State.new(opts)
  end
  state.generate(obj)
end
load(source, proc = nil, options = {}) → object 按一下以切換來源

傳回透過剖析給定的 source 所建立的 Ruby 物件。

  • 參數 source 必須是字串,或可轉換為字串

    • 如果 source 回應實例方法 to_strsource.to_str 會變成來源。

    • 如果 source 回應實例方法 to_iosource.to_io.read 會變成來源。

    • 如果 source 回應實例方法 readsource.read 會變成來源。

    • 如果下列兩項都為 true,來源會變成字串 'null'

      • 選項 allow_blank 指定為真值。

      • 來源,如上所定義,為 nil 或空字串 ''

    • 否則,source 會維持來源。

  • 參數 proc,如果已給定,必須是接受一個參數的 Proc。它會以遞迴方式呼叫每個結果(深度優先順序)。請參閱下列詳細資料。請注意:此方法用於序列化來自受信任使用者輸入的資料,例如來自您自己的資料庫伺服器或您控制下的客戶端,允許不受信任的使用者傳入 JSON 來源可能會很危險。

  • 參數 opts,如果已給定,會包含剖析選項的雜湊。請參閱 剖析選項。預設選項可透過方法 JSON.load_default_options= 進行變更。


如果未給定 proc,會如上修改 source 並傳回 parse(source, opts) 的結果;請參閱 parse

下列範例的來源

source = <<-EOT
{
"name": "Dave",
  "age" :40,
  "hats": [
    "Cattleman's",
    "Panama",
    "Tophat"
  ]
}
EOT

載入字串

ruby = JSON.load(source)
ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}

載入 IO 物件

require 'stringio'
object = JSON.load(StringIO.new(source))
object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}

載入檔案物件

path = 't.json'
File.write(path, source)
File.open(path) do |file|
  JSON.load(file)
end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}

當給定 proc

  • 如上修改 source

  • 從呼叫 parse(source, opts) 取得 result

  • 遞迴呼叫 proc(result)

  • 傳回最終結果。

範例

require 'json'

# Some classes for the example.
class Base
  def initialize(attributes)
    @attributes = attributes
  end
end
class User    < Base; end
class Account < Base; end
class Admin   < Base; end
# The JSON source.
json = <<-EOF
{
  "users": [
      {"type": "User", "username": "jane", "email": "[email protected]"},
      {"type": "User", "username": "john", "email": "[email protected]"}
  ],
  "accounts": [
      {"account": {"type": "Account", "paid": true, "account_id": "1234"}},
      {"account": {"type": "Account", "paid": false, "account_id": "1235"}}
  ],
  "admins": {"type": "Admin", "password": "0wn3d"}
}
EOF
# Deserializer method.
def deserialize_obj(obj, safe_types = %w(User Account Admin))
  type = obj.is_a?(Hash) && obj["type"]
  safe_types.include?(type) ? Object.const_get(type).new(obj) : obj
end
# Call to JSON.load
ruby = JSON.load(json, proc {|obj|
  case obj
  when Hash
    obj.each {|k, v| obj[k] = deserialize_obj v }
  when Array
    obj.map! {|v| deserialize_obj v }
  end
})
pp ruby

輸出

{"users"=>
   [#<User:0x00000000064c4c98
     @attributes=
       {"type"=>"User", "username"=>"jane", "email"=>"[email protected]"}>,
     #<User:0x00000000064c4bd0
     @attributes=
       {"type"=>"User", "username"=>"john", "email"=>"[email protected]"}>],
 "accounts"=>
   [{"account"=>
       #<Account:0x00000000064c4928
       @attributes={"type"=>"Account", "paid"=>true, "account_id"=>"1234"}>},
    {"account"=>
       #<Account:0x00000000064c4680
       @attributes={"type"=>"Account", "paid"=>false, "account_id"=>"1235"}>}],
 "admins"=>
   #<Admin:0x00000000064c41f8
   @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
# File ext/json/lib/json/common.rb, line 540
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
別名為:restore
load_file(path, opts={}) → object 按一下以切換原始碼

呼叫

parse(File.read(path), opts)

請參閱方法 parse

# File ext/json/lib/json/common.rb, line 248
def load_file(filespec, opts = {})
  parse(File.read(filespec), opts)
end
load_file!(path, opts = {}) 按一下以切換原始碼

呼叫

JSON.parse!(File.read(path, opts))

請參閱方法 parse!

# File ext/json/lib/json/common.rb, line 259
def load_file!(filespec, opts = {})
  parse!(File.read(filespec), opts)
end
merge_dump_options(opts, strict: NOT_SET) 按一下以切換原始碼
# File ext/json/lib/json/common.rb, line 642
def merge_dump_options(opts, strict: NOT_SET)
  opts = opts.merge(strict: strict) if NOT_SET != strict
  opts
end
parse(source, opts) → object 按一下以切換原始碼

傳回透過剖析給定的 source 所建立的 Ruby 物件。

引數 source 包含要剖析的字串。

引數 opts(如果已提供)包含剖析選項的雜湊。請參閱 剖析選項


source 是 JSON 陣列時,傳回 Ruby 陣列

source = '["foo", 1.0, true, false, null]'
ruby = JSON.parse(source)
ruby # => ["foo", 1.0, true, false, nil]
ruby.class # => Array

source 是 JSON 物件時,傳回 Ruby 雜湊

source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
ruby = JSON.parse(source)
ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}
ruby.class # => Hash

如需剖析所有 JSON 資料類型的範例,請參閱 剖析 JSON

剖析巢狀 JSON 物件

source = <<-EOT
{
"name": "Dave",
  "age" :40,
  "hats": [
    "Cattleman's",
    "Panama",
    "Tophat"
  ]
}
EOT
ruby = JSON.parse(source)
ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}

如果 source 不是有效的 JSON,則擲回例外狀況

# Raises JSON::ParserError (783: unexpected token at ''):
JSON.parse('')
# File ext/json/lib/json/common.rb, line 218
def parse(source, opts = {})
  Parser.new(source, **(opts||{})).parse
end
parse!(source, opts) → object 按一下以切換原始碼

呼叫

parse(source, opts)

source 以及可能已修改的 opts

JSON.parse 的差異

  • 選項 max_nesting(如果未提供)預設為 false,這會停用巢狀深度檢查。

  • 選項 allow_nan(如果未提供)預設為 true

# File ext/json/lib/json/common.rb, line 233
def parse!(source, opts = {})
  opts = {
    :max_nesting  => false,
    :allow_nan    => true
  }.merge(opts)
  Parser.new(source, **(opts||{})).parse
end
pretty_generate(obj, opts = nil) → new_string 按一下以切換原始碼

此處的引數 objoptsJSON.generate 中的引數 objopts 相同。

預設選項為

{
  indent: '  ',   # Two spaces
  space: ' ',     # One space
  array_nl: "\n", # Newline
  object_nl: "\n" # Newline
}

範例

obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}}
json = JSON.pretty_generate(obj)
puts json

輸出

{
  "foo": [
    "bar",
    "baz"
  ],
  "bat": {
    "bam": 0,
    "bad": 1
  }
}
# File ext/json/lib/json/common.rb, line 373
def pretty_generate(obj, opts = nil)
  if State === opts
    state, opts = opts, nil
  else
    state = JSON.create_pretty_state
  end
  if opts
    if opts.respond_to? :to_hash
      opts = opts.to_hash
    elsif opts.respond_to? :to_h
      opts = opts.to_h
    else
      raise TypeError, "can't convert #{opts.class} into Hash"
    end
    state.configure(opts)
  end
  state.generate(obj)
end

私人執行個體方法

restore
別名:load