如何使用Argonaut将嵌套JSON数组解析为Scala字符串数组并解决API识别问题
解决Argonaut API识别失败、提取JSON嵌套query字段的实操方案
核心问题排查
- 所有
decodeOption、Parse.parse、codec3识别失败的根本原因都是导入缺失、版本不匹配、参考内容过老:- Argonaut的所有扩展方法(比如字符串上的
decodeOption)都是靠隐式转换实现的,必须显式导入argonaut.Argonaut._才能触发,漏了这个导入所有方法都会报找不到符号 - 老教程里提到的
codec3是给3个字段的case类生成编解码器的老API,新版本Argonaut调整了该系列方法的签名和引用路径,直接抄多年前的社区代码自然识别不到 - 你提供的JSON本身存在语法错误:最外层多了一个冗余的闭合大括号,就算API配对正确,解析也会直接失败,修正后的正确JSON格式如下:
{ "TestModel" : [ {"query" : "select * from ci_lmaggregation.elementstest where hash_aggregation_key = 0 ALLOW FILTERING "}, {"query" : "select * from ci_lmaggregation.elementstest where hash_aggregation_key = 1 ALLOW FILTERING "}, {"query" : "select * from ci_lmaggregation.elementstest where hash_aggregation_key = 2 ALLOW FILTERING "} ] }
- Argonaut的所有扩展方法(比如字符串上的
- 需求完全可以实现和Python一致的简易取数逻辑,不需要提前定义复杂的case类或手写冗余编解码器
零类型绑定的最简实现(和Python JSON操作逻辑对齐)
不需要提前定义任何业务case类,直接按JSON路径取值,即可拿到所有query字符串:
// 必须导入完整的Argonaut扩展包,解决API找不到的问题 import argonaut._ import Argonaut._ val inputPath = "[path]/FeatureMapping.json" val jsonContent = scala.io.Source.fromFile(inputPath).mkString.trim // 解析JSON字符串,返回Either[ParseError, Json] val parseResult = Parse.parse(jsonContent) // 按路径直接取所有query值,组装成字符串数组 val queryArray = parseResult.toOption.map { rootJson => // 直接递归查找TestModel字段下所有嵌套的query值 (rootJson \\ "TestModel" --\\ "query") .flatMap(_.as[String].toOption) }.getOrElse(Nil)
上述代码完全等价于Python中的简易取数逻辑:
# 等价的Python实现 import json with open(inputPath) as f: data = json.load(f) query_array = [item["query"] for item in data["TestModel"]]
强类型场景的实现方式
如果需要把JSON映射成强类型对象方便后续维护,只需要定义和JSON结构对应的case类,用对应字段数量的casecodecN生成编解码器即可,不需要用和结构不匹配的codec3:
// 1. 定义和JSON结构完全匹配的case类 case class QueryEntry(query: String) case class ModelWrapper(TestModel: List[QueryEntry]) // 2. 为只有1个字段的QueryEntry生成编解码器(当前JSON结构没有3个字段的对象,完全用不到codec3) implicit val queryCodec: CodecJson[QueryEntry] = casecodec1(QueryEntry.apply, QueryEntry.unapply)("query") implicit val wrapperCodec: CodecJson[ModelWrapper] = casecodec1(ModelWrapper.apply, ModelWrapper.unapply)("TestModel") // 3. 直接解码成强类型对象提取字段 val typedQueries = jsonContent .decodeOption[ModelWrapper] .map(_.TestModel.map(_.query)) .getOrElse(Nil)
避坑提示
- 导入代码必须放在文件顶部,不能写在函数内部,否则隐式转换不会生效
- 参考社区教程时要匹配当前使用的Argonaut版本,6.2之后的版本和6.1及更早版本的API存在不兼容改动
- 写完JSON内容先做语法校验,避免冗余括号、逗号这类低级错误导致解析失败
内容的提问来源于stack exchange,提问作者troyblerg
相关产品推荐
相关产品推荐

