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

使用Scala解析嵌套JSON:遥测数据生成的多层JSON字段提取问题

Scala解析嵌套Telemetry JSON的解决方案

我完全理解你现在的困扰——多层嵌套的JSON确实容易让人头疼,尤其是Telemetry这种结构固定但层级深的数据。下面我给你分享两种Scala生态里最常用的JSON解析方案,分别基于Play JSON和Circe这两个主流库,你可以根据自己项目的依赖情况选择合适的实现方式。


方案一:使用Play JSON(Typesafe官方库)

Play JSON是Scala项目中非常常用的JSON处理库,API直观,和Play框架集成友好,当然也可以单独使用。

第一步:添加依赖

在你的build.sbt里加入Play JSON的依赖(版本可以根据需要调整):

libraryDependencies += "com.typesafe.play" %% "play-json" % "2.9.2"

第二步:定义数据模型

根据你的Telemetry JSON结构,创建对应的case class来映射层级结构。这里假设attributes里有interfaceName和status两个字段,你可以根据实际字段调整:

import play.api.libs.json._

// 映射attributes层级
case class InterfaceAttributes(interfaceName: String, status: String)
// 映射interfaceEntity层级
case class InterfaceEntity(attributes: InterfaceAttributes)
// 映射最外层的Telemetry数据
case class TelemetryData(
  version_str: String,
  node_id_str: String,
  encoding_path: String,
  collection_id: Long,
  collection_start_time: Long,
  collection_end_time: Long,
  msg_timestamp: Long,
  subscription_id: List[String],
  sensor_group_id: List[String],
  data_source: String,
  data: Map[String, InterfaceEntity] // 用Map来接收data下的动态key(比如interfaceEntity)
)

// 自动生成JSON格式转换器(implicit用于Play JSON的自动解析)
implicit val interfaceAttributesFormat: OFormat[InterfaceAttributes] = Json.format[InterfaceAttributes]
implicit val interfaceEntityFormat: OFormat[InterfaceEntity] = Json.format[InterfaceEntity]
implicit val telemetryDataFormat: OFormat[TelemetryData] = Json.format[TelemetryData]

第三步:解析并提取字段

接下来就可以解析JSON字符串,然后提取你需要的特定字段了:

// 你的Telemetry JSON示例字符串
val telemetryJson = """{ "version_str": "1.0.0", "node_id_str": "router-01", "encoding_path": "sys/intf", "collection_id": 241466, "collection_start_time": 0, "collection_end_time": 0, "msg_timestamp": 0, "subscription_id": [ ], "sensor_group_id": [ ], "data_source": "DME", "data": { "interfaceEntity": { "attributes": {"interfaceName": "GigabitEthernet0/0", "status": "up"} } } }"""

// 解析JSON字符串
val parseResult = Json.parse(telemetryJson).validate[TelemetryData]

// 处理解析结果
parseResult match {
  case JsSuccess(telemetry, _) =>
    // 提取你需要的字段,比如接口名称和状态
    val targetEntity = telemetry.data("interfaceEntity")
    println(s"接口名称: ${targetEntity.attributes.interfaceName}")
    println(s"接口状态: ${targetEntity.attributes.status}")
    // 其他字段同理,直接从telemetry对象中获取
  case JsError(errors) =>
    println(s"解析失败,错误详情: $errors")
}

方案二:使用Circe(函数式风格库)

Circe是基于Cats的函数式JSON库,适合喜欢函数式编程风格的开发者,API更灵活,支持自动推导和手动编写编解码器。

第一步:添加依赖

在build.sbt里加入Circe的核心、泛型推导和解析器依赖:

libraryDependencies ++= Seq(
  "io.circe" %% "circe-core" % "0.14.6",
  "io.circe" %% "circe-generic" % "0.14.6",
  "io.circe" %% "circe-parser" % "0.14.6"
)

第二步:定义数据模型与编解码器

同样先定义case class,然后用Circe的泛型推导自动生成解码器:

import io.circe._
import io.circe.generic.semiauto._
import io.circe.parser.decode

case class InterfaceAttributes(interfaceName: String, status: String)
case class InterfaceEntity(attributes: InterfaceAttributes)
case class TelemetryData(
  version_str: String,
  node_id_str: String,
  encoding_path: String,
  collection_id: Long,
  collection_start_time: Long,
  collection_end_time: Long,
  msg_timestamp: Long,
  subscription_id: List[String],
  sensor_group_id: List[String],
  data_source: String,
  data: Map[String, InterfaceEntity]
)

// 自动推导解码器
implicit val interfaceAttributesDecoder: Decoder[InterfaceAttributes] = deriveDecoder[InterfaceAttributes]
implicit val interfaceEntityDecoder: Decoder[InterfaceEntity] = deriveDecoder[InterfaceEntity]
implicit val telemetryDataDecoder: Decoder[TelemetryData] = deriveDecoder[TelemetryData]

第三步:解析并提取字段

用Circe的decode方法解析JSON,然后处理结果:

val telemetryJson = """{ "version_str": "1.0.0", "node_id_str": "router-01", "encoding_path": "sys/intf", "collection_id": 241466, "collection_start_time": 0, "collection_end_time": 0, "msg_timestamp": 0, "subscription_id": [ ], "sensor_group_id": [ ], "data_source": "DME", "data": { "interfaceEntity": { "attributes": {"interfaceName": "GigabitEthernet0/0", "status": "up"} } } }"""

// 解析JSON
decode[TelemetryData](telemetryJson) match {
  case Right(telemetry) =>
    val targetAttrs = telemetry.data("interfaceEntity").attributes
    println(s"提取到节点ID: ${telemetry.node_id_str}")
    println(s"接口状态: ${targetAttrs.status}")
  case Left(error) =>
    println(s"解析出错: ${error.getMessage}")
}

额外提示:处理动态/未知字段

如果你的attributes字段是动态的(不确定具体有哪些字段),可以把attributes的类型定义为JsValue(Play JSON)或Json(Circe),然后手动提取字段:

Play JSON示例

case class InterfaceEntity(attributes: JsValue)
// 提取字段
val status = (telemetry.data("interfaceEntity").attributes \ "status").asOpt[String].getOrElse("unknown")

Circe示例

case class InterfaceEntity(attributes: Json)
// 提取字段
val status = telemetry.data("interfaceEntity").attributes.hcursor.get[String]("status").getOrElse("unknown")

这样即使字段有变化,也能灵活处理,避免解析失败。

内容的提问来源于stack exchange,提问作者user3521305

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:34:31