广告位联系
返回顶部
分享到

Ruby解析处理YAML和json格式数据

ruby 来源:互联网 作者:佚名 发布时间:2022-09-21 09:20:34 人浏览
摘要

Ruby处理YAML Ruby的标准库YAML基于Psych:https://ruby-doc.org/stdlib-2.6.2/libdoc/psych/rdoc/Psych.html require yaml之后,为大多数的基本数据类型都提供了to_ yaml()方法,用于将各数据类型的对象转换为y

Ruby处理YAML

Ruby的标准库YAML基于Psych:https://ruby-doc.org/stdlib-2.6.2/libdoc/psych/rdoc/Psych.html

require 'yaml' 之后,为大多数的基本数据类型都提供了 to_ yaml() 方法,用于将各数据类型的对象转换为yaml格式。

例如:

1

2

3

4

5

6

7

8

require 'yaml'

require 'set'

 

p "hello world".to_yaml

p 123.to_yaml

p %w(perl shell php).to_yaml

p ({one: 1, two: 2}).to_yaml

p Set.new([1,2,3]).to_yaml

得到:

1

2

3

4

5

"--- hello world\n"

"--- 123\n"

"---\n- perl\n- shell\n- php\n"

"---\n:one: 1\n:two: 2\n"

"--- !ruby/object:Set\nhash:\n  1: true\n  2: true\n  3: true\n"

也可以使用YAML.dump()方法实现和to_yaml相同的功能,它还可以写入文件。

1

2

3

4

users = [{name: 'Bob', permissions: ['Read']},

 {name: 'Alice', permissions:['Read', 'Write']}]

 

File.open("/tmp/a.yml","w") { |f| YAML.dump(users, f) }

查看文件:

1

2

3

4

5

6

7

8

---

- :name: Bob             #=> 注意,保留了hash源数据中的符号

  :permissions:

  - Read

- :name: Alice

  :permissions:

  - Read

  - Write

用YAML.load()从YAML中读取数据:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

require 'yaml'

 

pp YAML.load(DATA)

 

__END__

mysql:

  passwd: P@ssword1!

  user: root

  port: 3306

  other1: nil

  other2: false

  other3: ""

  hosts:

    - ip: 10.10.1.1

      hostname: node1

    - ip: 10.10.1.2

      hostname: node2

得到:

1

2

3

4

5

6

7

8

9

10

{"mysql"=>

  {"passwd"=>"P@ssword1!",      #=> 注意,key是String而非Symbol

   "user"=>"root",

   "port"=>3306,

   "other1"=>"nil",

   "other2"=>false,

   "other3"=>"",

   "hosts"=>

    [{"ip"=>"10.10.1.1", "hostname"=>"node1"},

     {"ip"=>"10.10.1.2", "hostname"=>"node2"}]}}

如果想让hash的key是符号而非字符串,可以设置选项symbolize_names: true:

1

pp YAML.load(DATA, symbolize_names: true)

需要注意,YAML可以将对象进行序列化,所以有几方面注意事项:

  • 在反序列化的时候需要也require涉及到的文件,例如对Set类型序列化后,在反序列化时如不require 'set'则无法还原对象
  • 有些底层对象不能序列化,包括IO流、Ruby代码对象Proc、Binding等
  • 不要反序列化不被信任的数据对象(比如用户输入的数据),此时可使用safe_load(),它默认只允许加载以下几种类型的数据:
    • TrueClass
    • FalseClass
    • NilClass
    • Numeric
    • String
    • Array
    • Hash
  • 如果确实想要加载额外的数据类型,可以在safe_load()中指定参数permitted_classes: []或permitted_symbols: []

Ruby处理Json数据

转为json格式字符串

使用JSON.generate()可以将对象或数组转换为JSON格式的数据:

1

2

3

4

5

6

7

8

9

require 'json'

p JSON.generate "abc"

p JSON.generate 123

p JSON.generate true

p JSON.generate nil

p JSON.generate [2,3,4]

p JSON.generate({name: "junmajinlong", age: 23})

require 'set'

p JSON.generate(Set.new([1,23,44]))

得到:

1

2

3

4

5

6

7

"\"abc\""

"123"

"true"

"null"

"[2,3,4]"

"{\"name\":\"junmajinlong\",\"age\":23}"

"\"#<Set: {1, 23, 44}>\""

当require 'json'后,很多ruby类型都具备了一个to_json的方法,可以直接将该类型的数据转换为json数据:

1

2

p ({name: "junmajinlong", age: 23}).to_json

p (Set.new([1,23,44])).to_json

得到:

1

2

"{\"name\":\"junmajinlong\",\"age\":23}"

"\"#<Set: {1, 23, 44}>\""

此外,JSON.dump()也可以将对象转换为JSON格式的字符串,而且它还支持写入文件:

1

2

hsh = {name: "junmajinlong", age: 23}

File.open("/tmp/a.json", "w") {|f| JSON.dump(hsh, f)}

json格式字符串转为Ruby对象

要从json格式字符串转为ruby对象,有一些选项可设置,参考https://ruby-doc.org/stdlib-2.7.1/libdoc/json/rdoc/JSON.html#method-i-parse,比如*symbolize_names*选项表示是否将json object中的key解析为符号类型的key,如果设置为false,则解析为字符串的key。

要将json格式的字符串解析为Ruby数据类型(Hash),使用JSON.parse(),

1

2

3

4

5

6

require 'json'

 

hsh = '{"name": "junmajinlong", "age": 23}'

 

p JSON.parse(hsh)

p JSON.parse(hsh, symbolize_names: true)

注意,上面的json字符串必须是合理的json数据,比如key必须使用双引号包围而不能使用单引号,字符串必须使用双引号包围,等等。比如"{'name': 'junmajinlong', 'age': 23}"就不是合理的json字符串。

要从json文件中读取json数据并转换为Ruby数据,使用load():

1

2

3

4

5

6

data = File.open("/tmp/a.json") do |f|

  JSON.load(f)

end

 

pp data

#=> {"name"=>"junmajinlong", "age"=>23}

自定义对象的转换方式

json支持的数据类型有:

  • 字符串
  • 数值
  • 对象
  • 数组
  • 布尔
  • Null

从一种语言的数据转换为Json数据时,如果数据类型也是JSON所支持的,可直接转换,但如果包含了JSON不支持的类型,则可能报错,也可能以一种对象字符串的方式保存,这取决于对应的实现。

可以在对象中定义as_json实例方法来决定对象如何转换为json字符串,再定义类方法from_json()来决定如何从json字符串中恢复为一个对象。

例如,

1

2

3

4

5

6

7

8

9

10

11

12

13

14

require 'json'

require 'date'

 

class Person

  attr_accessor :name, :birthday

  def initialize name, birthday

    @name = name

    @birthday = DateTime.parse(birthday)

  end

end

 

File.open("/tmp/p.json", "w") do |f|

  JSON.dump(Person.new("junmajinlong", "1999-10-11"), f)

end

查看保存的json数据:

1

2

$ cat /tmp/p.json

"#<Person:0x00007fffc7e575d0>"

定义as_json和frmo_json:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

require 'json'

require 'date'

 

class Person

  attr_accessor :name, :birthday

   

  def initialize name, birthday

    @name = name

    @birthday = DateTime.parse(birthday)

  end

   

  def as_json

    {

      name: @name,

      birthday: @birthday.strftime("%F")

    }

  end

 

  def self.from_json json

    data = JSON.parse(json)

    new(data["name"], data["birthday"])

  end

end

之后要序列化、反序列化该对象,可:

1

2

3

4

5

data = Person.new("junmajinlong", "1999-10-11").as_json

p data

 

p1=Person.from_json(JSON.dump data)

p p1.birthday

如果是读写json文件,可:

1

2

3

4

5

6

7

8

9

10

person1 = Person.new("junmajinlong", "1999-10-11")

File.open("/tmp/p.json", "w") do |f|

  JSON.dump(person1.as_json, f)

end

 

p1 = File.open("/tmp/p.json") do |f|

  Person.from_json(f.read)

  # Person.from_json(JSON.load(f).to_json)

end

p p1

几种JSON解析工具的性能测试

测试了json标准库、oj和fast_josnparser解析json的性能,测试项包括:

  • 从文件中加载并解析json字符串为ruby对象
  • 从内存json字符串中解析json字符串为ruby对象
  • 带有symbolize_keys/symbolize_names转换时的解析
  • json标准库和oj将ruby对象dump为json字符串
  • json标准库和oj将ruby对象dump为json字符串保存到文件

注:

  • fast_jsonparser没有dump功能,只有解析json字符串功能
  • oj在将对象转换为json字符串时,可能会丢失数据的精度,比如浮点数的精度

测试的json字符串数量大约50M。

测试了ruby 2.7.1和ruby 3.0.1两个版本,gem包的版本信息如下:

1

2

3

fast_jsonparser (0.5.0)

json (default: 2.5.1)

oj (3.11.7)

测试代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

require 'benchmark'

require 'json'

require 'oj'

require 'fast_jsonparser'

 

# warm

json_file='test'  # 文件大小大约50M

str = File.read(json_file)

 

######## JSON

 

puts " load file ".center(80, '-')

Benchmark.bm(30) do |x|

  x.report("JSON.load:") { File.open(json_file){ |f| JSON.load(f) } }

  x.report("Oj.load_file:") { Oj.load_file(json_file) }

  x.report("FastJsonparser.load:") { FastJsonparser.load(json_file) }

end

 

puts

puts " load file with symbolize_keys ".center(80, '-')

Benchmark.bm(30) do |x|

  x.report("JSON.load:") { File.open(json_file){ |f| JSON.load(f, nil, symbolize_names: true, create_additions: false) } }

  x.report("Oj.load_file:") { Oj.load_file(json_file, symbol_keys: true) }

  x.report("FastJsonparser.load:") { FastJsonparser.load(json_file, symbolize_keys: true) }

end

 

puts

puts " parse str ".center(80, '-')

Benchmark.bm(30) do |x|

  x.report("JSON.parse:") { JSON.parse(str) }

  x.report("Oj.load:") { Oj.load(str) }

  x.report("FastJsonparser.parse:") { FastJsonparser.parse(str) }

end

 

puts

puts " parse str with symbolize_keys ".center(80, '-')

Benchmark.bm(30) do |x|

  x.report("JSON.parse:") { JSON.parse(str, symbolize_names: true) }

  x.report("Oj.load:") { Oj.load(str, symbol_keys: true) }

  x.report("FastJsonparser.parse:") { FastJsonparser.parse(str, symbolize_keys: true) }

end

 

obj = JSON.parse(str, symbolize_names: true)

 

puts

puts " dump JSON to str ".center(80, '-')

Benchmark.bm(30) do |x|

  x.report("JSON.dump:") { JSON.dump(obj) }

  x.report("Oj.dump:") { Oj.dump(obj) }

end

 

puts

puts " dump JSON to file ".center(80, '-')

Benchmark.bm(30) do |x|

  x.report("JSON.dump:") { File.open('0_json_dump', 'w') {|f| JSON.dump(obj, f) } }

  x.report("Oj.to_file:") { Oj.to_file('0_oj_dump', obj) }

end

测试结果:

Ruby 2.7.1中:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

---------------------------------- load file -----------------------------------

                                     user     system      total        real

JSON.load:                       1.591831   0.058021   1.649852 (  1.738119)

Oj.load_file:                    1.350385   0.057684   1.408069 (  2.434268) <-慢

FastJsonparser.load:             0.653968   0.103258   0.757226 (  0.848913) <-快

 

------------------------ load file with symbolize_keys -------------------------

                                     user     system      total        real

JSON.load:                       1.212617   0.039052   1.251669 (  1.349545)

Oj.load_file:                    1.432059   0.098950   1.531009 (  2.679610) <-慢

FastJsonparser.load:             0.695538   0.008384   0.703922 (  0.797081) <-快

 

---------------------------------- parse str -----------------------------------

                                     user     system      total        real

JSON.parse:                      1.343596   0.000000   1.343596 (  1.350368)

Oj.load:                         1.133612   0.000000   1.133612 (  1.140939)

FastJsonparser.parse:            0.701701   0.012340   0.714041 (  0.720296) <-快

 

------------------------ parse str with symbolize_keys -------------------------

                                     user     system      total        real

JSON.parse:                      1.250775   0.000000   1.250775 (  1.258796)

Oj.load:                         1.131296   0.000000   1.131296 (  1.138020)

FastJsonparser.parse:            0.697433   0.015962   0.713395 (  0.719439) <-快

 

------------------------------- dump JSON to str -------------------------------

                                     user     system      total        real

JSON.dump:                       1.374611   0.028454   1.403065 (  1.403081)

Oj.dump:                         1.025049   0.040184   1.065233 (  1.065246) <-快

 

------------------------------ dump JSON to file -------------------------------

                                     user     system      total        real

JSON.dump:                       1.234362   0.040246   1.274608 (  1.369214)

Oj.to_file:                      1.168707   0.000000   1.168707 (  1.270957)

Ruby 3.0.1中:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

---------------------------------- load file -----------------------------------

                                     user     system      total        real

JSON.load:                       1.362151   0.083610   1.445761 (  1.569754)

Oj.load_file:                    1.343601   0.182046   1.525647 (  2.684472) <-慢

FastJsonparser.load:             2.634435   0.052734   2.687169 (  2.776105) <-慢

 

------------------------ load file with symbolize_keys -------------------------

                                     user     system      total        real

JSON.load:                       1.287954   0.018572   1.306526 (  1.409770)

Oj.load_file:                    1.478750   0.043847   1.522597 (  2.668882) <-慢

FastJsonparser.load:             2.717857   0.006164   2.724021 (  2.822728) <-慢

 

---------------------------------- parse str -----------------------------------

                                     user     system      total        real

JSON.parse:                      1.242225   0.008661   1.250886 (  1.304554)

Oj.load:                         1.097922   0.000000   1.097922 (  1.110031)

FastJsonparser.parse:            2.602679   0.017232   2.619911 (  2.634604) <-慢

 

------------------------ parse str with symbolize_keys -------------------------

                                     user     system      total        real

JSON.parse:                      1.368262   0.000000   1.368262 (  1.380730)

Oj.load:                         1.332349   0.000000   1.332349 (  1.346331)

FastJsonparser.parse:            2.706804   0.007238   2.714042 (  2.726935) <-慢

 

------------------------------- dump JSON to str -------------------------------

                                     user     system      total        real

JSON.dump:                       1.724653   0.009250   1.733903 (  1.733912)

Oj.dump:                         1.298235   0.030041   1.328276 (  1.328279) <-快

 

------------------------------ dump JSON to file -------------------------------

                                     user     system      total        real

JSON.dump:                       1.765664   0.040595   1.806259 (  1.905785)

Oj.to_file:                      1.228744   0.020309   1.249053 (  1.349684) <-快

=end

性能测试结论:

  • (1).ruby 3之前,fast_jsonparser非常快,但是Ruby 3中的fast_jsonparser很慢
  • (2).OJ解析本地json字符串的性能比标准库json性能稍好,但oj从文件中加载并解析json的速度很慢
  • (3).OJ将ruby对象解析为json字符串的效率比json标准库性能好

即:

1

2

3

4

5

6

7

8

9

10

dump:

Oj.dump > JSON.dump

 

ruby3 之前:

FastJsonparser.load > JSON.load > Oj.load_file

FastJsonparser.parse > Oj.load > JSON.parse

 

ruby3 之后:

JSON.load > Oj.load_file > FastJsonparser.load

Oj.load > JSON.parse > FastJsonparser.parse

multi_json

有一个名为multi_json的gem包,它提供多种json包的功能,默认采用OJ作为json的适配引擎。它支持下面几种json适配器:

  • Oj Optimized JSON by Peter Ohler
  • Yajl Yet Another JSON Library by Brian Lopez
  • JSON The default JSON gem with C-extensions (ships with Ruby 1.9+)
  • JSON Pure A Ruby variant of the JSON gem
  • NSJSONSerialization Wrapper for Apple’s NSJSONSerialization in the Cocoa Framework (MacRuby only)
  • gson.rb A Ruby wrapper for google-gson library (JRuby only)
  • JrJackson JRuby wrapper for Jackson (JRuby only)
  • OkJson A simple, vendorable JSON parser

如果oj已被require,则默认采用oj处理json,如果oj没有被require,而是require了yajl,则采用yajl处理json,依次类推。

它提供了load()和dump()方法:

1

2

3

4

5

6

load(json_str, options = {})

  options:

    symbolize_keys: true, false

    adapter:  oj, json_gem, yajl, json_pure, ok_json

 

dump(object, options = {})


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://www.junmajinlong.com/ruby/ruby_yaml_json/
相关文章
  • CentOS7下安装Ruby3.2.4的实施路径介绍
    一、CentOS版本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [user@zt ~]$ cat /etc/os-release NAME=CentOS Linux VERSION=7 (Core) ID=centos ID_LIKE=rhel fedora VERSION_ID=7 PRETTY_NAME=Cen
  • Ruby解析处理YAML和json格式数据
    Ruby处理YAML Ruby的标准库YAML基于Psych:https://ruby-doc.org/stdlib-2.6.2/libdoc/psych/rdoc/Psych.html require yaml之后,为大多数的基本数据类型都提供了to_
  • 安装Ruby和安装Rails详细步骤介绍

    安装Ruby和安装Rails详细步骤介绍
    rbenv安装Ruby rbenv可以管理多个版本的ruby。可以分为3种范围(或者说不同生效作用域)的版本: local版:本地,针对各项目范围(只在某个目录下
  • Ruby使用GDBM操作DBM数据存储方法实例介绍
    DBM简介 dbm(database manager) 是使用本地文件来存储数据的数据库,基于Key -Value对数据进行存储、读取,且有些dbm的实现( berkeley db)还支持BTree索
  • Ruby变量的介绍
    变量是持有可被任何程序使用的任何数据的存储位置。 Ruby 支持五种类型的变量。 一般小写字母、下划线开头:变量(Variable)。 $开头:全
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计