You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Ruby中将JSON解析为异构嵌套结构体?

Ruby JSON解析为指定结构体并校验无效键

核心思路

直接使用JSON.parse的object_class参数无法满足嵌套结构体解析和键校验需求,因此采用先转普通Hash→键校验→手动映射结构体的流程:

  1. 将JSON解析为Ruby原生Hash
  2. 校验各层级的键是否符合预期,无效键直接抛出异常
  3. 手动将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 23:45:10