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

Scala如何读取及遍历键值对与类型均未知的JSON对象

Hey there! Let's tackle these two common Scala JSON challenges head-on—reading and traversing JSON where neither the key-value pairs nor data types are known in advance. I'll walk you through practical approaches using popular Scala JSON libraries, since raw manual parsing is rarely worth the effort.

1. Reading JSON with Unknown Structure and Types

When dealing with completely unstructured JSON, the goal is to parse it into a flexible, type-agnostic representation that can handle any JSON value. Two widely used libraries for this are Circe and Play JSON—let's cover both.

Using Circe

Circe provides a Json algebraic data type (ADT) that encapsulates all valid JSON types (null, boolean, number, string, array, object). First, add the Circe dependencies to your build.sbt:

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

Then parse your JSON string into a Json value, handling potential parsing errors:

import io.circe._, io.circe.parser._

val unknownJsonString = """{"randomKey": 42, "anotherKey": ["foo", true, null], "nested": {"deep": "value"}}"""

// Parse the string into an Either[ParsingFailure, Json]
val parsedJson: Either[ParsingFailure, Json] = parse(unknownJsonString)

// Safely extract the Json value (handle errors in real code!)
val json: Json = parsedJson.getOrElse(Json.Null)

Using Play JSON

Play JSON uses JsValue as its flexible JSON representation. Add the Play JSON dependency to build.sbt:

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

Parse the JSON string like this:

import play.api.libs.json._

val unknownJsonString = """{"randomKey": 42, "anotherKey": ["foo", true, null], "nested": {"deep": "value"}}"""

// Parse into a JsResult[JsValue] (similar to Either for error handling)
val parsedResult: JsResult[JsValue] = Json.parse(unknownJsonString)

// Extract the JsValue (handle errors appropriately in production!)
val jsValue: JsValue = parsedResult.getOrElse(JsNull)
2. Traversing the Unknown JSON Object

Once you have your flexible JSON representation, you'll need to traverse it recursively to handle all possible values. Let's implement traversal functions for both libraries.

Traversing with Circe

Use pattern matching on the Json ADT to handle each type, and recurse into arrays and objects:

def traverseCirceJson(json: Json, indent: String = ""): Unit = json match {
  case Json.Null => println(s"${indent}Null")
  case Json.Boolean(b) => println(s"${indent}Boolean: $b")
  case Json.Number(n) => println(s"${indent}Number: $n")
  case Json.String(s) => println(s"${indent}String: '$s'")
  case Json.Array(arr) =>
    println(s"${indent}Array (size ${arr.size}):")
    arr.foreach(traverseCirceJson(_, indent + "  "))
  case Json.Object(obj) =>
    println(s"${indent}Object (${obj.size} keys):")
    obj.foreach { case (key, value) =>
      println(s"${indent}  Key: '$key'")
      traverseCirceJson(value, indent + "    ")
    }
}

// Call the function with our parsed Json
traverseCirceJson(json)

This will print out every element in the JSON, with indentation to show nested structure.

Traversing with Play JSON

Similarly, pattern match on JsValue subtypes and recurse:

def traversePlayJson(jsValue: JsValue, indent: String = ""): Unit = jsValue match {
  case JsNull => println(s"${indent}Null")
  case JsBoolean(b) => println(s"${indent}Boolean: $b")
  case JsNumber(n) => println(s"${indent}Number: $n")
  case JsString(s) => println(s"${indent}String: '$s'")
  case JsArray(arr) =>
    println(s"${indent}Array (size ${arr.size}):")
    arr.foreach(traversePlayJson(_, indent + "  "))
  case JsObject(fields) =>
    println(s"${indent}Object (${fields.size} keys):")
    fields.foreach { case (key, value) =>
      println(s"${indent}  Key: '$key'")
      traversePlayJson(value, indent + "    ")
    }
}

// Call the function with our parsed JsValue
traversePlayJson(jsValue)

Key Notes

  • Always handle parsing errors in production code—don't use getOrElse with a default unless you're sure it's safe. Use Either/JsResult pattern matching to handle failures gracefully.
  • Both libraries offer more advanced features (like decoding to case classes if you later discover a structure), but these approaches are perfect for truly unknown JSON.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:37:42