如何在Ruby中将JSON解析为异构嵌套结构体?
Ruby JSON解析为指定结构体并校验无效键
核心思路
直接使用JSON.parse的object_class参数无法满足嵌套结构体解析和键校验需求,因此采用先转普通Hash→键校验→手动映射结构体的流程:
- 将JSON解析为Ruby原生Hash
- 校验各层级的键是否符合预期,无效键直接抛出异常
- 手动将Hash中的数据映射为指定的结构体实例(包括嵌套的
B实例数组)
步骤1:定义结构体并添加基础校验
先定义A和B结构体,同时在初始化方法中添加必填项和类型校验,确保实例数据合法:
# 定义B结构体,对应JSON中的语言项 B = Struct.new(:language, :text) do def initialize(language, text) super raise ArgumentError, "language不能为空" if language.nil? || language.empty? raise ArgumentError, "text不能为空" if text.nil? || text.empty? end end # 定义A结构体,对应顶级JSON对象 A = Struct.new(:name, :languages, :index) do def initialize(name, languages, index) super raise ArgumentError, "name不能为空" if name.nil? || name.empty? raise ArgumentError, "languages必须是B实例数组" unless languages.is_a?(Array) && languages.all? { |item| item.is_a?(B) } raise ArgumentError, "index必须是Hash类型" unless index.is_a?(Hash) end end
步骤2:实现键校验函数
编写函数校验各层级的键是否为允许的字段,存在无效键时抛出异常:
# 校验顶级JSON对象的键 def validate_top_level_keys(hash) allowed_keys = %w[name languages index].to_set invalid_keys = hash.keys.to_set - allowed_keys raise ArgumentError, "存在无效顶级键: #{invalid_keys.join(', ')}" unless invalid_keys.empty? end # 校验单个语言项的键 def validate_language_item_keys(item_hash) allowed_keys = %w[title text].to_set invalid_keys = item_hash.keys.to_set - allowed_keys raise ArgumentError, "语言项存在无效键: #{invalid_keys.join(', ')}" unless invalid_keys.empty? end
步骤3:完整解析流程
将JSON解析为Hash后,依次完成校验和结构体映射:
# 示例JSON字符串 json_str = <<~JSON { "name": "Greetings", "languages": [ { "title": "English", "text": "Good day" }, { "title": "French", "text": "Bonjour" } ], "index": { "Good": "English", "day": "English", "Bonjour": "French" } } JSON # 1. 解析为原生Hash parsed_hash = JSON.parse(json_str) # 2. 校验顶级键 validate_top_level_keys(parsed_hash) # 3. 处理languages数组,转为B实例 languages = parsed_hash['languages'].map do |lang_hash| validate_language_item_keys(lang_hash) # 将JSON中的title映射为B的language字段 B.new(lang_hash['title'], lang_hash['text']) end # 4. 创建A实例 a_instance = A.new(parsed_hash['name'], languages, parsed_hash['index']) # 测试输出 puts a_instance.name # 输出: Greetings a_instance.languages.each do |b| puts "#{b.language}: #{b.text}" end # 输出: # English: Good day # French: Bonjour puts a_instance.index # 输出: {"Good"=>"English", "day"=>"English", "Bonjour"=>"French"}
错误场景测试
如果JSON中存在无效键,会直接抛出异常:
# 包含无效顶级键的JSON invalid_json = <<~JSON { "name": "Greetings", "text": "多余字段", "languages": [ { "title": "English", "text": "Good day" } ], "index": {} } JSON parsed_invalid = JSON.parse(invalid_json) validate_top_level_keys(parsed_invalid) # 抛出异常: ArgumentError: 存在无效顶级键: text
内容的提问来源于stack exchange,提问作者toolforger
相关产品推荐
相关产品推荐

