当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Ruby JSON模块用法及代码示例


本文简要介绍ruby语言中 JSON模块 的用法。

JavaScript 对象表示法 (JSON)

JSON 是一种轻量级的数据交换格式。

JSON 值是以下之一:

  • 双引号文本:"foo"

  • 编号:11.02.0e2

  • 布尔值:truefalse

  • 空:null

  • 数组:值的有序列表,用方括号括起来:

    ["foo", 1, 1.0, 2.0e2, true, false, null]
  • 对象:名称/值对的集合,用花括号括起来;每个名称都是双引号文本;这些值可以是任何 JSON 值:

    {"a": "foo", "b": 1, "c": 1.0, "d": 2.0e2, "e": true, "f": false, "g": null}

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, opts)

  • JSON.parse!(source, opts)

其中

  • source 是一个 Ruby 对象。

  • opts 是一个 Hash 对象,其中包含控制输入允许和输出格式的选项。

两种方法的区别在于 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 哈希:

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 标量。

String :

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

空值:

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 (boolean) 指定是否在 source 中允许 NaN Infinity MinusInfinity ;默认为 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]
输出选项

Option symbolize_names (boolean) 指定返回的Hash键是否应该是Symbols;默认为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 (Class) 指定要用于每个 JSON 对象的 Ruby 类;默认为哈希。

默认情况下,哈希:

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 (Class) 指定要用于每个 JSON 数组的 Ruby 类;默认为数组。

默认情况下,数组:

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

使用类集:

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) ,其中

  • source 是一个 Ruby 对象。

  • opts 是一个 Hash 对象,其中包含控制输入允许和输出格式的选项。

从数组生成 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

当源既不是 Array 也不是 Hash 时,生成的 JSON 数据取决于源的类。

当源是 Ruby Integer 或 Float 时, JSON.generate 返回一个包含 JSON 数字的字符串:

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

当源是 Ruby 字符串时, JSON.generate 返回一个包含 JSON 字符串的字符串(使用 double-quotes):

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 (Integer) 指定 obj 中的最大嵌套深度;默认为 100

使用默认值 100

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

太深:

# Raises JSON::NestingError (nesting of 2 is too deep):
JSON.generate(obj, max_nesting: 2)
输出选项

默认格式选项生成最紧凑的 JSON 数据,全部在一行上,没有空格。

您可以使用这些格式化选项使用空格以更开放的格式生成 JSON 数据。另见 JSON.pretty_generate

  • 选项 array_nl (String) 指定要在每个 JSON 数组之后插入的字符串(通常是换行符);默认为空字符串 ''

  • 选项 object_nl (String) 指定要在每个 JSON 对象之后插入的字符串(通常是换行符);默认为空字符串 ''

  • Option indent (String) 指定用于缩进的字符串(通常是空格);默认为空字符串,'';默认为空字符串,'';除非选项 array_nlobject_nl 指定换行符,否则无效。

  • 选项 space (String) 指定要在每个 JSON 对象对中的冒号之后插入的字符串(通常是空格);默认为空字符串 ''

  • 选项 space_before (String) 指定要在每个 JSON 对象对中的冒号之前插入的字符串(通常是空格);默认为空字符串 ''

在此示例中,首先使用 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 添加

当你“round trip”一个非字符串对象从 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 additions 来保留原始对象。添加是 ruby 类的扩展,因此:

  • JSON.generate 在 JSON 字符串中存储更多信息。

  • JSON.parse 使用选项 create_additions 调用,使用该信息创建适当的 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 它的来源:

  • 大十进制:require 'json/add/bigdecimal'

  • 复杂:require 'json/add/complex'

  • 日期:require 'json/add/date'

  • 日期时间:require 'json/add/date_time'

  • 异常:require 'json/add/exception'

  • 开放结构:require 'json/add/ostruct'

  • 范围:require 'json/add/range'

  • 理性:require 'json/add/rational'

  • 正则表达式:require 'json/add/regexp'

  • 设置:require 'json/add/set'

  • 结构:require 'json/add/struct'

  • 符号:require 'json/add/symbol'

  • 时间:require 'json/add/time'

为了减少标点混乱,下面的示例显示了通过 puts 而不是通常的 inspect 生成的 JSON,

大十进制:

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

开放结构:

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)

相关用法


注:本文由纯净天空筛选整理自ruby-lang.org大神的英文原创作品 JSON模块。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。